I have a React hook:
const useWidgets = () => {
const [skip, setSkip] = useState(0);
const take = 20;
async function getItems() {
try {
console.log('skip is always 0 here', skip);
const rsp = await apiGetWidgets({ skip });
setSkip((state) => state + take);
} catch (err) {
console.log(err);
}
}
useEffect(() => {
getItems();
}, []);
return { getItems, skip };
};
And I have a functionalComponent, that consumes the hook:
const Infinite: FC = () => {
const { getItems, skip } = useWidgets();
useEffect(()=> {
setTimeout(getItems, 4000)
}, [])
console.log('skip is updated here to latest value', skip);
return <div>
{skip}
</div>
};
When skip
is updated by setSkip
the value change is updated in the functional Component but that change is not reflected in the useWidget
hook, skip
is always zero.
Is this because the useWidgets hook closed over the initial value of skip
which starts out at zero?
I thought any subsequent calls to getItems
would be able to access the new value of skip
but it remains at zero. Every time the functional component Infinite
gets re-rendered I thought a new call to useWidgets
would be called and the latest value of skip
would be maintained, but I guess it reinitializes at zero?
Can anyone explain the behavior of why I cant access current state in the useWidgets
hook, but the functionalComponent Infinite
can?
No, the closure is not happening inside the
useWidgets
but it is happening inside theuseEffect
of theInfinite
component.The
getItems
in thatuseEffect
is the one from the initial render of the component, so it uses the "first" definedgetItems
. It just delays its execution due to the timeout.If you add a button inside the
Infinite
component that invokes thegetItems
you will see that it is getting the correct one.See demo at https://stackblitz.com/edit/af-react-sandbox-d5spdh?file=index.js