When I control both inputValue and selectedItem:
<Downshift
onInputValueChange={onInputValueChange}
inputValue={inputValue}
onChange={onChange}
selectedItem={value} // nullable but not optional (will never be undefined)>
{...}
</Downshift>
I would expect that itemToString is never called. However it seems to be called when the selectedItem prop changes. In my application, Item is an object so this causes an error to be logged to the console because the default itemToString is being called. I end up having to provide this this silly itemToString function where I re-provide the inputValue:
<Downshift
onInputValueChange={onInputValueChange}
inputValue={inputValue}
onChange={onChange}
selectedItem={value} // nullable but not optional (will never be undefined)
itemToString={() => inputValue}>
{...}
</Downshift>
Can you help me understand whey itemToString would be called in this scenario or if this is a bug?
I'm using downshift version: 3.1.12
Your question is a valid one, but itemToString was not made to cover only the generation of the inputValue. It is also used to also compute an aria-live message, see getA11yStatusMessage in utils.js. We may use it for something else in the future as well.
Since we cannot assume that you want the same controlled inputValue in every other place we use the itemToString, you should provide us the string equivalent for your Item objects. It's the contract between your app and Downshift. If you use strings as items, cool. If not, just tell us how to make a string out of them.
I don't think this is a bug at our end. Let me know if you need any more info. Thanks!
Hey @silviuavram that makes total sense, thanks for sharing the context. I can see why you'd need a string representation of a value for things like aria-live.
I'm still seeing a scenario I don't understand though. When I'm providing an explicit inputValue and a value Downshift passes the inputValue to my input element until value is updated. Then Downshift instead passes the result of itemToString to my input element. I would have expected it to continue to pass the inputValue I provide.
Is this expected behavior? I was hoping by suppling inputValue I could provide some simple itemToString function "for the computers" so to speak and keep my more complex display logic in one place (outside Downshift).
Your problem is probably in selectItem function. The problem is probably the fact that the inputValue is changed to the autocontrolled value in the state setter, and itemToString is already called before that.
Yes, we can improve our autocontrolled logic. It may need a big refactoring however, and bugs may appear. At the moment, I am not planning to do that myself, as I have some other things that appear more pressing, like the cypress tests. But if you can make our autocontrolled logic bulletproof and create a PR, you're awesome.
Until then, you still need to pass that itemToString function.
I'm also seeing the input's value being set to the result of itemToString even when I'm passing in an explicit inputValue - this seems like a bug.
Here's a simple repro based on the official first example, simply made controlled. Start typing in some characters and then blurring鈥擠ownshift forcefully resets the inputValue.
Got surprised by the same thing. It doesn't make much sense why it should be resetting user input on blur without selecting an item. What if a user just needs to do something else, he certainly does not want to lose what he typed so far.
Behaviour should be this one: https://github.com/downshift-js/downshift/issues/679
will close this issue as we will use the one above to track
Most helpful comment
Behaviour should be this one: https://github.com/downshift-js/downshift/issues/679
will close this issue as we will use the one above to track