I don't understand why I'm getting infinite loop in useClick I see that I change state value inside useEffect using setVal but useEffect should work only on onClick as specified in second param. I thought that it is because the param onClick i pass is memoized but the callback is not called(i checked that using console.log('go set')
function useClick(onClick, setVal, val) {
React.useEffect(() => {
console.log('Click');
setVal(val + 1);
}, [onClick]);
}
const Home = () => {
const [val, setVal] = React.useState(0);
const incrementOnClick = React.useCallback(() => {
console.log('go set');
setVal(val + 1);
} , [setVal, val]);
useClick(incrementOnClick, setVal, val);
return <div>
<div>{val}</div>
<button onClick={incrementOnClick}>Click me</button>
</div>
}
val
and setVal
will change on every render, which in turn will cause incrementOnClick
to become a new function reference, and your useClick
effect will always be invoked.
You could instead give a function as first argument to setVal
. This function gets the current val
as argument and returns the new value. This way incrementOnClick
will always be the same function.
const { useEffect, useState, useCallback } = React;
function useClick(onClick, setVal, val) {
useEffect(() => {
console.log("Click");
setVal(val + 1);
}, [onClick]);
}
const Home = () => {
const [val, setVal] = useState(0);
const incrementOnClick = useCallback(() => {
console.log("go set");
setVal(val => val + 1);
}, []);
useClick(incrementOnClick, setVal, val);
return (
<div>
<div>{val}</div>
<button onClick={incrementOnClick}>Click me</button>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
The code above shows how you could get away from the infinite loop and could be valuable for experimentation, but most of it isn't necessary. You could write the same functionality like this instead:
const { useState } = React;
const Home = () => {
const [val, setVal] = useState(1);
return (
<div>
<div>{val}</div>
<button onClick={() => setVal(val + 1)}>Click me</button>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With