2

I recently added asynchronous code (Sockets) to a project and every time the state is called the original state value is passed. So far I've tried passing a callback to setState, and although that seemed to help, I ran into another issue the state no longer updated, i.e. the child component stopped re-rendering.

Below is the code which is most relevant. If you want another piece of code, don't hesitate to ask.

This code is called to update the state, which is a series of nested dictionaries, one named card contains an array of objects. The code updates the card we are calling it from, calls a function which returns a modified copy of the object and then passed that to a callback. Previously this was done by passing a copy of the original state, but that has the same issue.

const updateItem = useCallback(
    (id, field, additionalData, value) => {
      const { card, index } = findCard(id);
      console.log("Updating item " + id);
      const updatedCard = updateObject(card, additionalData, field, value);
      setData((prevState) => {
          const newState = {...prevState};
          newState["HIT"]["data"][index] = updatedCard;
          return newState;
      });
    },
    [data]
  );

The update function is called from an input in a child component. The state updates, but next time it is called the userInput value is "".

       <input
          type="text"
          id="message"
          autoComplete="on"
          placeholder="Type a message"
          value={props.Item['userInput']}
          onChange={e => {props.updateItem(props.Item["id"],
                      "userInput",
                        {},
                  e.target.value);
          }
          } 
        />

Any help would be greatly appreciated!

Felix Labelle
  • 153
  • 3
  • 15
  • Can you clarify what `setData` does? If it is a function returned by a `useState` hook, then you are forgetting to pass this back in as the `value` for the input component (See https://reactjs.org/docs/forms.html#controlled-components). You need to use it's corresponding `data` object as the value in the input, not `props.Item.userInput`. – tobiasfried Jan 06 '20 at 19:08
  • setData is returned by `useState` and `data` is iterated over and passed as the Item props. I'm pretty sure that the correct item is being updated, but I'll double check. The reason I think the issue is deeper than that is that I tried doing something similar elsewhere with a much simpler case and had the same problem. What solved it was using a callback for the `set` function. – Felix Labelle Jan 06 '20 at 21:04
  • The simpler example I was talking about was the subject of this question (https://stackoverflow.com/questions/59566569/incorrect-state-upon-hook-callback/59566670#59566670) – Felix Labelle Jan 06 '20 at 21:06
  • I haven't tested this, but it looks like you're not including all the necessary dependencies for the memoized function -- `prevState` is a closure and will always represent its initial value, unless added as a dependency. – tobiasfried Jan 06 '20 at 21:42

0 Answers0