-
Notifications
You must be signed in to change notification settings - Fork 932
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
handleStateChange confusion around controlling isOpen #206
Comments
Thanks for the issue @jole78, I knew we'd have to deal with this eventually. Here's how things work... There are 4 parts of state in downshift: As noted above, when you control any state, we don't call There are a lot of reasons state can change and it's not easily determinable without the It's undocumented because I didn't love the API and most folks can get a long way without needing to know it exists. But I think that things have been around long enough to say that no better API will materialize and we can set this one in stone.
Do they allow you to control the I'm thinking the solution is to simply document the Happy to discuss alternative solutions. |
@kentcdodds thx for the reply. It’s Friday night in Sweden so I’ll have to think this over and get back to you next week. Have a great weekend Kent. |
@kentcdodds if I'm not misreading how React Bootstrap uses this they allow you to set rootClose on an overlay component and if you do you must specify an onHide event handler (that becomes a required prop). That usually involves you controlling the "show" prop on the overlay (via your state)...so yes, they allow you to control the isOpen state of the overlay. ref (https://react-bootstrap.github.io/components.html#overlays). Is that perhaps a solution?? Something like you can set a prop on downshift (like rootClose or something) and then downshift will call your onHide event handler when that occurs withing downshift. Truthfully I feel this code below forces me to know a little too much about the inner workings of downshift, as you also clearly agreed with...right? handleStateChange = changes => {
const { isOpen, type } = changes;
if (type === DownShift.stateChangeTypes.mouseUp) {
this.isOpen = isOpen;
}
}; Another solution might be another stateChangeType which more clearly would indicate that the user clicked outside of the downshift component? |
I can understand your concern. One thing that I want to avoid is adding a bunch of props to do things which can be done with what's already available. However, I think this is a pretty common use case, so I'm willing to add a prop for an I think the implementation should be quite simple. Just in time for hacktoberfest 😉 Steps to solve:
Please make sure to follow the CONTRIBUTING.md. Thanks! |
Note, first person to "claim" this issue by saying "I'm working on this right now" will have their PR iterated on and merged :) |
I'm working on this right now |
Looks fair enough. Saw that react-select has something similar called onClickOutside or something like that so it seems reasonable. Thx |
Hey everyone, I wanted to report a possible bug (unless I misread the documentation), and I don't mean to steal @jole78's spotlight, but I think this issue is related to what I'm talking about. I've been playing around with Downshift and I realized that there may be a bug related to how onStateChange provides the wrong For example... I copied the provided 'Multiple Select' sample, and just made a modification by rendering an extra Downshift dropdown component below the first one. With that said, when you click an item in the dropdown list, the changeType from onStateChange is now Since it provides Try it out for yourself here. https://codesandbox.io/s/8pywk9vo8 Any ideas how to resolve this?
|
Yeah, that's a really odd thing you're doing there... I don't have the time to explain what's going on (someone else can take a crack at it if you want), but if you explain what you're trying to accomplish then maybe I can help you know how to do it properly... |
Hi @kentcdodds. First of all, I'm assuming this upcoming onOuterClick functionality will resolve what I'm talking about, correct? Anyways, I'm trying to accomplish rendering a Downshift dropdown component in each accordion panel's Everything worked fine, until I wanted to essentially close a Downshift dropdown on blur, using this implementation:
This actually worked too for the first accordion panel. But when I started to add more than one accordion panels dynamically (with the Downshift dropdown component in the content of each accordion panel), then the bug occurs. I realized regardless of the accordion panels being open/closed, the content is always rendered but hidden in some way. With that said I experimented further by just rendering two Downshift dropdown components next to each other and I also replicated the bug. Earlier today, I was able to work around a fix for my situation by just rendering one of the Downshift dropdown components at a time based on the current active accordion. This way, no more than one Downshift component can be rendered at a time, working around the issue. With all of that said, that's my story and how I came across this. :) |
This PR is not ready to be merged yet. When merged, this will fix #206 This PR does the following (Will appreciate early feedback and comments):- 1. Add onOuterClick description to README. I can remove the link to a specific issue from there 2. Add onOuterClick to propTypes with type PropTypes.func 3. Call this.props.onOuterClick as a callback to reset function when it is called under onMouseUp event 4. Add a test case for newly added functionality. This is still incomplete. I started with the test case expecting it to fail in its current state where I open the menu and simulate a outside click with click on document.body. With the current state of the onOuterClick callback this should have resulted in isOpen to be false there by failing the test but it is not the case. Exploring. Also, to simulate the click on document.body. I borrowed the function `mouseDownAndUp` from `downshift.lifecycle.js`. I can either move this test over there or expose that function in a better way than duplicating. Let me know your feedback on the approach? Also, please point out if you believe that I understood the problem incorrectly.
Ah, the problem is that you're sharing the You can solve this by keeping the In any case, |
@kentcdodds ah, duh... Thanks! 👍 |
@kentcdodds Found this issue to be useful; especially your rational for using handleStateChange. So is it certain that the Downshift.stateChangeTypes will be an official part of the API? Or do you have an issue to gather consensus? If so would like to PR to update the docs for these usages. |
Yeah, I think we'll make the stateChangeTypes official. Anyone can feel free to make a pull request to document it. |
Problem description:
I'm trying to create a dropdown that contains a couple of choices that the user can select (a checkbox list one could say). It's basically a multiple select thingy.
So I wan't to keep the dropdown menu open while the user is interacting with it.
So, I know that I then have to to take "control" over the isOpen prop and supply that to downshift. That all works fine.
The issue that I'm facing is that if the user clicks outside the downshift component (the root component) the menu should close.
I found this piece of code in the example:
That seems to do the trick...but...for one it seems a little bit "complicated" (or how should I put it) and I really don't know why I need this and how it all works together.
Suggested solution:
Either better documentation about this type of situation or some other means to tell downshift that when the user clicks outside just close it, ignoring isOpen prop.
React Bootstrap has a prop called rootClose on its overlays that handles this for example.
The text was updated successfully, but these errors were encountered: