downshift version: 2.0.7node version: 8.11.1npm (or yarn) version: 6.0.1Relevant code or config
const CountrySelect = props => (
<Downshift
onSelect={props.selectCountryAction}
defaultSelectedItem={props.selectedCountry}
itemToString={item => item.name}
>
// ...
What you did:
We are storing the selected item (country) in our Redux state. This is initially populated on the server (via query string) and passed to Downshift via defaultSelectedItem. If the user changes their country using Downshift we dispatch an action to update this in the Redux state.
We are also persisting this Redux state in localStorage, so if the user refreshes the page everything renders with the initial state, then updates to show their previously entered details (we load from localStorage in componentDidMount).
What happened:
The problem is that although our Redux state updates to whatever the localStorage version of the selected country is (and correctly updates Downshift's props), Downshift doesn't seem to update its internal state. So the selected item is correctly set to the localStorage value, (as is the defaultSelectedItem prop), but the actual inputValue in Downshift's state is mismatched鈥攊t gets stuck on whatever value it was initially rendered with.
It seems like maybe #101 wasn't actually fixed?
Reproduction repository: https://codesandbox.io/s/r5w1x035xp
Suggested solution:
It's possible we're abusing the concept of "default" values. It feels like maybe if we want to keep Downshift in sync with our Redux store we would be better off making it a fully controlled component?
Otherwise is there any reason for Downshift not to update its internal state when it re-renders with new props?
@oliverjam I'll just give a piece of my opinion on this. From what you described and showed in codesandbox, It seems like you want to update defaultSelectedItem. However, if you look at the documentation, defaultSelectedItem is only meant to assign the initial value to Downshift. Essentially, defaultSelectedItem is only used in the constructor of Downshift, as below:
https://github.com/paypal/downshift/blob/e76224815ba2b62f843c14041984d3b421a62b24/src/downshift.js#L121-L128
So, this indicates that you only want to leverage defaultSelectedItem (same applied to all defaultXXX props, where XXX is any control prop) iff you want Downshift to be uncontrolled. However, in your case, you clearly want it to be controlled.
So, my advice would be to leverage selectedItem control prop, and sync that with your store.
Yeah you're right. I guess it just felt weird because we weren't _really_ controlling it until we started persisting the value in localStorage.
It makes that that default props only set initial values, thanks!
I LOVE YOU @franklixuefei
Most helpful comment
@oliverjam I'll just give a piece of my opinion on this. From what you described and showed in codesandbox, It seems like you want to update
defaultSelectedItem. However, if you look at the documentation,defaultSelectedItemis only meant to assign the initial value toDownshift. Essentially,defaultSelectedItemis only used in the constructor ofDownshift, as below:https://github.com/paypal/downshift/blob/e76224815ba2b62f843c14041984d3b421a62b24/src/downshift.js#L121-L128
So, this indicates that you only want to leverage
defaultSelectedItem(same applied to alldefaultXXXprops, whereXXXis any control prop) iff you wantDownshiftto be uncontrolled. However, in your case, you clearly want it to be controlled.So, my advice would be to leverage
selectedItemcontrol prop, and sync that with your store.