downshift-js / downshift

🏎 A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete, combobox or select dropdown components.
http://downshift-js.com/
MIT License
12.05k stars 933 forks source link

Impossible to override input received on `onInputValueChange` after item selection #759

Open wild-lotus opened 5 years ago

wild-lotus commented 5 years ago

Relevant code or config

const stateReducer = (state, changes) => {
  switch (changes.type) {
    case Downshift.stateChangeTypes.clickItem:
    case Downshift.stateChangeTypes.keyDownEnter:
    case Downshift.stateChangeTypes.controlledPropUpdatedSelectedItem:
      return {
        ...changes,
        inputValue: "input overriden"
      };
    default:
      return changes;
  }
};

What you did:

I tried to override via stateRducer the inputValue after some item is selected.

What happened:

The internal state gets updated, but then I receive from onInputValueChange the selected item string, instead of the inputValue in state.

Reproduction repository:

It is the basic autocomplete with minimum modifications and some explanations: Codesandbox

Problem description:

I can't get the inputValue that I have overridden via stateReducer from onInputValueChange after an item is selected. I always get the selected item string instead. This behaviour seems to be unexpected.

Suggested solution:

I have no suggestion yet! Can you confirm this is an unexpected behaviour?

silviuaavram commented 5 years ago

It may be strange, but apparently it's the result of https://github.com/downshift-js/downshift/issues/217 you can check there and see why they did it at that time.

However what is important is what actually you try to achieve. If this blocks a scenario then we can discuss on that and come up with a solution. Using stateReducer and on{prop}Changed at the same time for the same state prop is probably a sign that you are doing something wrong. :D

wild-lotus commented 5 years ago

Thank you for your quick reply @silviuavram ! :D

I will explain what I am trying to achieve (a bit simplified): I have inputValue and selectedItem as controlled props, and when I blur input, I want to clear selection but keep the input.

I have created in CodeSandbox one example reproducing the problem, with the 5 variations I can think of to address the issue:

  1. Using onBlur event handler and setState
  2. Using onBlur event handler and controlled props
  3. Using stateReducer
  4. Using onStateChange event handler and setState
  5. Using onStateChange event handler and controlled props

In the end I tracked down that issue to what I pointed on my first message.

silviuaavram commented 5 years ago

I've been caught up with the work for useSelect but will look over as soon as possible. Thanks!

shallow-alchemy commented 4 years ago

I am having a similar issue today. I want to restore a blank input value on blur (for example, when changes.inputvalue length is 0 in the state reducer) to the previous input value (which I store in state outside of Downshift). I can't make that happen. Any progress on a solution for this from anyone?

shallow-alchemy commented 4 years ago

I was able to make this work. The reason why I couldn't get the stateReducer to listen to a blur was because I was managing the event outside of Downshift. Once I realized this, I was able to trigger a "closeMenu" on blur, and then listen for the blurEvent. But this would be solved with the ability to force a state update through the stateReducer for custom state changes. Is there a way to do that?