-1

Here's a snippet if my code. When I call filteredData(), the state is not updated. I have to click the button twice before the state updates. This is an old project that I am updating using hooks. I previously used a callback function after setting the state, but I can't do that with hooks.

function change(event) {
  let name = event.target.name;
  let value =
  event.target.type === "checkbox"
    ? event.target.checked
    : event.target.value;

setState((prevState) => ({ ...prevState, [name]: value }));
filteredData()

}

Patrick Roberts
  • 44,815
  • 8
  • 87
  • 134
  • Can you show the definition of `filteredData()`? – Patrick Roberts Jun 13 '21 at 17:07
  • you also can't do that regardless of *hooks* because setting state in react is done async, therefore code that comes after cannot rely of the state to have changed. This is why there is a `useEffect` hook. – vsync Jun 13 '21 at 17:28

2 Answers2

0

This is because setState is an async function and if you need to do any task immediately after setting the state...you should do it in a callback.

In class Component

function change(event) {
  let name = event.target.name;
  let value =
  event.target.type === "checkbox"
    ? event.target.checked
    : event.target.value;

 this.setState(
    (prevState) => {
      return {
        ...prevState,
        [name]: value
      };
    },
    () => {
      filteredData();
    }
  );
}

In hooks As there is no callback for setter in hooks, we can use useEffect on change of the state.

useEffect(() => filteredData(), [state])
sakshya73
  • 1,516
  • 2
  • 10
  • 20
  • This is incorrect. The `setState()` in the question is a hook, not a class component method. Notice the lack of `this`. You can't pass a callback to the hook setter function. Also notice it was explicitly stated in the question that _"I previously used a callback function after setting the state, but I can't do that with hooks."_ – Patrick Roberts Jun 13 '21 at 17:24
  • Right @PatrickRoberts...looking at the `setState` i thought it's a class component. We can use a `useEffect` to run the `filterData` function on change of state. – sakshya73 Jun 13 '21 at 17:41
  • 1
    You've just blatantly copied the existing answer, and there's no reason to keep the part of your answer that's wrong. – Patrick Roberts Jun 13 '21 at 17:44
0

This is what the useEffect hook is for, since the setState hook does not have a callback like setState has in class components.

useEffect(() => filteredData(), [state])

The function in useEffect will run every time state changes. As saksh73 said, setState is async, however it does not return promise so you cannot call then on it or await it. You have to use useEffect to react to state changes as shown.

Luka
  • 9
  • 1
  • 1
    Keep in mind this proposed solution will also invoke `filteredData()` on initial render, which may not be what OP wants. – Patrick Roberts Jun 13 '21 at 17:26
  • 1
    to further what Patrick said, you can check if the state if what you are expect it to be before calling `filterData` and this might be enough to block it from being called when the component mounts, depending how your state looks like. – vsync Jun 13 '21 at 17:31