Skip to content
Advertisement

React useState, setState and {state} in return

I come across the rendering issue with React State.
The problem is that {state} in return get value one beat late.
But the console log in handleChange shows right value.
If the previous value of state is 9, current value of state value is 10 then the console.log({state}) in handleChange shows 10 and the <span>{state}<span> in return shows 9.
It looks different from other state async problem.
I can’t understand why this happened.

const [findText, setFindText] = useState("");
const [findCount, setFindCount] = useState(0);
const handleChange = (e) => {
    let str = e.target.value;
    setFindText(str);

    let cnt = 0;
    doxDocument.map((docx) => {
      cnt += docx.src.split(findText).length - 1;
    });
    setFindCount(cnt);
    console.log({findCount})
};
return( 
<div>
  <input
    type="text"
    value={findText}
    onChange={handleChange}
  />
  <span>{findCount} found <span>
</div>
);

Advertisement

Answer

Two problems…

  1. findText will not have been updated to the new value when you use it in split(). Either use str instead or calculate findCount in a memo or effect hook with a dependency on findText.
  2. You’re completely misusing filter(). Use reduce() to calculate a computed sum
  const [findText, setFindText] = useState("");
  const findCount = useMemo(
    () =>
      findText
        ? doxDocument.reduce(
            (sum, { src }) => sum + src.split(findText).length - 1,
            0
          )
        : 0,
    [findText, doxDocument] // may not need doxDocument
  );

  return (
    <div id="App">
      <input
        type="text"
        value={findText}
        onChange={(e) => setFindText(e.target.value)}
      />
      <span>{findCount} found</span>
    </div>
  );

Edit autumn-river-jslqtt

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement