Home > Mobile >  Search bar in react works, but experiencing very strange behaviour
Search bar in react works, but experiencing very strange behaviour

Time:05-09

In a component when an input is provided it dispatches the input to a reducer

const changeSearchTerm = (e) => {
    setSearchTerm(e.target.value)
    dispatch(userActions.searchByName(searchTerm));
  }

Then the reducer takes that value and tries to filter the array based on that input

searchByName: (state, action) => {
      state.search = action.payload;

      let newArray = state.users.filter((user) =>
        user.name.toLowerCase().includes(state.search.toLowerCase())
      );

      state.users = newArray;
    },

Then this whole array is displayed in one of the other components. The search bar works to some extent: When you start typing into the search bar it only starts to work after second input. In console I have noticed that if you type "Timmothy" it will only register "Timmoth" in the state. Additionaly, if I delete text from the input, the state of the array doesn't update and stays the same even though the input value changes.

So what happens currently is if you start typing in the search bar, it updates the array, but always only registers second to last keystroke. Additionally, if you delete input from the search bar, it doesn't register. The value changes, but the array stays with only few items left.

I have tried to not use the additional variable to store the state and do it like this

state.users.filter((user) =>
       user.name.toLowerCase().includes(state.search.toLowerCase())

But then absolutely nothing happens. Would appreciate if someone could tell me what I'm missing here

EDIT

This is the component that receives that input

<input onChange={changeSearchTerm} type="text" value={searchTerm}></input>

And the searchTerm value is saved in useState - const [searchTerm, setSearchTerm] = useState("");

CodePudding user response:

From what I can tell, it only works after the second input because of this block:

const changeSearchTerm = (e) => {
    setSearchTerm(e.target.value)
    dispatch(userActions.searchByName(searchTerm));
  }

State setters like setSearchTerm are actually asynchronous. This means that after you call setSearchTerm, on the next line the value of searchTerm is still the old value.

You can instead do one of the following:

const changeSearchTerm = (e) => {
    setSearchTerm(e.target.value)
    dispatch(userActions.searchByName(e.target.value));
}
const changeSearchTerm = (e) => {
    setSearchTerm(e.target.value, () => {
      // This callback runs only after state has changed
      dispatch(userActions.searchByName(searchTerm));
    });
}

Edit: Sorry I missed that you used useState/functional. You can use useEffect:

const changeSearchTerm = (e) => {
    setSearchTerm(e.target.value);
}

useEffect(() => {
   if (searchTerm.length > 0) {
     dispatch(userActions.searchByName(searchTerm));
   }
}, [searchTerm]);

This way your dispatch will correctly run whenever searchTerm's value changes for sure.

https://reactjs.org/docs/react-component.html#setstate

  • Related