Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Snackbar] Reopens when message prop is an element #3186

Closed
iamzhouyi opened this issue Feb 5, 2016 · 30 comments
Closed

[Snackbar] Reopens when message prop is an element #3186

iamzhouyi opened this issue Feb 5, 2016 · 30 comments
Labels
bug 🐛 Something doesn't work component: snackbar This is the name of the generic UI component, not the React module!

Comments

@iamzhouyi
Copy link

This bug happened only when the "message" prop passed as an element(not string)
When the snackbar rendered with same props, it triggers snackbar hide and show..

The reason is the message prop could be an object that never be equal with last one
qq 20160205145647

@alitaheri alitaheri added the bug 🐛 Something doesn't work label Feb 5, 2016
@alitaheri
Copy link
Member

We plan on removing state from these components entirely so this check will never have to happen 😁

@oliviertassinari
Copy link
Member

The state is here to perform the animation. From my perspective, event if we use react-motion to remove the state, the check will still be needed.

@alitaheri
Copy link
Member

Hmmm you have a point O.o

@theosherry
Copy link
Contributor

I've reproduced this bug using a FontIcon element as the message for the Snackbar, and having the Snackbar be re-rendered while it's still open:

element_message_cropped

After a second of opening the Snackbar, the state is changed and the Snackbar re-renders, without it's properties having changed, resulting in the bug:
element_message

I've made a PR to add a custom equality tester callback as a property of Snackbar, which addresses this bug.

@oliviertassinari
Copy link
Member

I'm wondering if the best fix for this wouldn't be on the user side.
Why not memoizing the message property that's passed down to the <Snackbar /> component?

@theosherry
Copy link
Contributor

Hmm, yeah that does seem like a better solution. I wonder if there should be a warning in the docs that using an element or array type node for the message will require some care in this regard.

@oliviertassinari
Copy link
Member

I wonder if there should be a warning in the docs that using an element or array type node for the message will require some care in this regard.

I can't find a way to display such warning 😕. Any idea?

@mbrookes mbrookes changed the title [snackbar] a bug when message prop passed as an element [Snackbar] Reopens when message prop is an element Feb 21, 2016
@iamzhouyi
Copy link
Author

if I pass a same key prop on the element, it that possible to determine it' same one?

@theosherry
Copy link
Contributor

@oliviertassinari I just added a bit of a warning in the message documentation: #3416

@theosherry
Copy link
Contributor

@yinickzhou I think the best solution is to actually use the same element if you want the Snackbar to treat it as the same element.

I'm not sure how your code is set up, but an idea is to have the message prop be a function call in which you check if the element should be changed — if it should be changed, make, store, and return the new element; if not, retrieve and return the current message, which should have been stored somewhere.

@oliviertassinari
Copy link
Member

@yinickzhou I like this key idea 👍.

So, what about adding an optional messageId property that would be used instead of the nextProps.message !== this.props.message check when provided? Something like

let messageChanged = false;

if (nextProps.messageId) {
  if (nextProps.messageId !== this.props.messageId ) {
     messageChanged = true;
  }
} else if (nextProps.message !== this.props.message) {
   messageChanged = true;
}

@iamzhouyi
Copy link
Author

@thefivetoes I understand why the same element is important, I just think that's not straightforward for the users.
I prefer @oliviertassinari's solution :)

@thefivetoes
Copy link

@yinickzhou I think you mean to name check @theosherry?

@iamzhouyi
Copy link
Author

yes, sorry about that @thefivetoes

@theosherry
Copy link
Contributor

@yinickzhou I agree it's not all that clear when using Snackbar with an elementmessage what the behaviour will be when it happens to re-render while it's open, which is why I think something has to be changed.

I prefer the solution of having the user ensure the message element doesn't change, because it keeps the Snackbar component more focused; and though the added property might make the component easier to use in this particular case, adding a superfluous property makes the component more difficult to pick up and use in the general case.

@oliviertassinari
Copy link
Member

@theosherry @yinickzhou Thanks for the feedbacks. We have merged the PR regarding documenting the behavior. I would say, let's close this issue and see how people react. If this is still an issue, we can reopen it and start looking for better solution.

@rsteckler
Copy link

I would prefer the messageId solution proposed by @oliviertassinari

The use case I'm running into is that I want the snackbar to stay on the screen with a 60 second countdown inside of it. I'm using an interval to count down the seconds, storing it in state, then pulling it into the Snackbar:

         <Snackbar
          open={this.state.startNotificationOpen}
          message={'Watch this fancy countdown: ' + this.state.countdown}
        />

Obviously the message is different every time, but I want the snackbar to persist on the screen. Allowing me to pass a messageId would solve my problem, and the more general case of dynamic content in Snackbars.

@oliviertassinari
Copy link
Member

@rsteckler That sounds like a valid use case. I'm reopening the issue.

@mbrookes
Copy link
Member

IMHO, this is an edge use-case, out of spec, and isn't really what the Snackbar is intended for, so @rsteckler should implement a custom component (using Snackbar as inspiration) rather than adding logic to Snackbar to support it.

@oliviertassinari
Copy link
Member

That's definitly an edge use-case.

I think that it would be great to provide a stateless version of the Snackbar so people like @rsteckler can implement their own logic.

@mbrookes
Copy link
Member

mbrookes commented Mar 27, 2016

That's a good point, although I would still be wary of implementing an additional prop to control that behaviour in the current implementation.

What if this functionality was tied to the autoHideDuration prop?

If that is set, the component is then inherently being used statefully, so the current behaviour for re-animating on message change would apply.

If autoHideDuration isn't set, then the component is being controlled statelessly through the open prop, so no animation of the message changes.

This would satisfy both use cases with no additional props, and minimal additional logic.

@rsteckler
Copy link

I think the above recommendation works. It basically puts the responsibility for expiring and queuing snackbars in the hands of the developer. I'm wondering, just for clarity, if having a new prop, 'stateless' with a default value of false would help. If stateless == true, then autoHideDuration is ignored.

It just seems more explicit from a documentation point of view, rather than having a side effect attached to autoHideDuration even though they're very closely tied.

@oliviertassinari
Copy link
Member

What if this functionality was tied to the autoHideDuration prop?

That's one way to fix it, but I think that we have a better one.
I think that it's the right moment to follow #2784, and split the actual Snackbar component into two separate one.

We could create a new Snackbar.stateless.js component as simple as possible. And make the Snackbar.js use it internally.
People may not need the Snackbar.js component, that's fine. For instance, I won't use it, I could move the message show / hide logic into my redux's reducers and use the Snackbar.stateless.js component.

@mbrookes @rsteckler What do you think?

@mbrookes
Copy link
Member

I think #2784 would have Snackbar.js be stateless by default, and add a stateful version that wraps it. Not sure how much of ReactStated we'd get to use. @alitaheri - would this be a good place to start implementing that?

@alitaheri
Copy link
Member

@mbrookes Since Snackbar doesn't have imperative methods, it's a good place for it 👍 I'll try to make a demo for it.

@juneidy
Copy link

juneidy commented Apr 26, 2016

For what it's worth, I found a workaround by having the message in an array. The source is using === checks which will check for array reference. As long as you are using the same array reference, no reopens will happen.

@oliviertassinari oliviertassinari added the component: snackbar This is the name of the generic UI component, not the React module! label Dec 18, 2016
@mbrookes mbrookes added the next label Jan 15, 2017
@azaslavsky
Copy link

@juneidysoo do you mind providing an example using the array formulation? I still can't quite get it to work.

@azaslavsky
Copy link

@oliviertassinari, I'm a little confused as to how I would memoize @theosherry's example in this comment. Do you mind giving me a short snippet describing how the FontIcon child component in that example could be memoized to pass the this.props.message === nextProps.message check mentioned at the start of this thread?

@juneidy
Copy link

juneidy commented Jan 17, 2018

@azaslavsky My solution is almost the same as @oliviertassinari memoization.
Having the elements (or your message) in an array and keep using the same array and pass it to Snackbar on the proceeding render cycle, you will pass the check message check as equal.

Unfortunately I cannot easily provide you any example code because I have since moved on to other UI library.

P.S. why are you still using this old version? it's 2 years old lol

@Angelk90
Copy link
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: snackbar This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants