Skip to content
Advertisement

Stale closures with react hooks and click events

I have created a codesandbox for easier debugging:
https://codesandbox.io/s/hardcore-dirac-nh4iz?file=/src/App.tsx

I have built a DataList component that I use like:

function App() {
  const [count, setCount] = useState(0);
  const countRef = useRef(count);

  const handleSelect = () => {
    setCount(count + 1);
    countRef.current = count + 1;
    console.log({ count });
  };

  return (
    <>
      <p>Stale closures prevent the count state from displaying correctly</p>
      <DataList.List label="testing">
        {data.map((d) => (
          <DataList.Item key={d} onSelect={handleSelect}>
            {d} {count}
          </DataList.Item>
        ))}
      </DataList.List>
    </>
  );
}

All of the functionality is handled inside of a useListBox hook, which includes taking the onSelect prop from each child and binding that to a click event on the List itself. However, a stale closure is preventing the count value from updating.

I would appreciate any help with this, as stale closures have yet to click for me.

I suspect, I need the onSelect to be a dependency on the handleClickEvent callback, but not sure.

Advertisement

Answer

The problem is the way your useEffectOnMount is defined. You need to factor in changes even after the mount whenever your children update as well. Change it from useEffectOnMount to useEffect and things will work :-

Forked sandbox – https://codesandbox.io/s/friendly-fog-inv8h?file=/src/components/DataList/DataList.tsx

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