I'm trying to convert a React class component into a React function component.
There is an onChange
function that is called both inside the component and from outside.
When calling a function component function, the useState
hook takes the initial value. When I'm using the old class component way, everything works correctly. Why is this happening, and how to solve this problem?
const MyInput = (props) => {
const { someLib, ...otherProps } = props;
const [test, setTest] = useState(1); // console show 1,2,3, etc
useEffect(() => {
someLib && someLib.addCallback(onChange);
}, []);
const onChange = (event) => {
setTest(test + 1) // this function can called inside MyInput, and from someLib,
// when it called from someLib, 'test' is reset, but in class component everything good
}
}
The problem is that onChange
is a stale closure. What you need to do is make onChange
look like this:
const onChange = (event) => {
setTest(oldTest => oldTest +1)
}
Alternatively you could add test
to the dependency array in your useEffect
make sure to do cleanup though. (You should be doing this anyways but it is even more important now)
useEffect(() => {
someLib && someLib.addCallback(onChange);
return () => {
someLib.removeCallback(onChange);
}
}, [someLib, test]);
technically if you are doing this latter method you would want to useCallback
const onChange = useCallback((event) => {
setTest(test + 1);
}, [test]);
useEffect(() => {
someLib && someLib.addCallback(onChange);
return () => {
someLib.removeCallback(onChange);
}
}, [someLib, onChange]);
the benefit of this is that you don't have to keep track of the dependencies of onChange
in a different place. The dependency list for onChange
is now close.