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