This is how I'm updating a custom hook's state based on the prop passed to it:
const useCustomHook = (prop: number) => {
const [state, setState] = useState(prop);
// this is how I'm currently updating state
// when the props change.
useEffect(() => {
setState(prop);
}, [prop]);
return state;
};
// it's usage
const [localState, setLocalState] = useState(0);
const hookState = useCustomHook(localState);
But the problem with above approach is that the return state
of the custom hook is going to run first, returning the old value before running the useEffect
callback and updating the hook's state and then returning the new state. This will cause the main component to render twice.
Now you may ask, what's the big deal if it renders twice? It can lead to bugs. For example, the custom hook could be a count-down, implementing setInterval, that comes down to 0, but when I reset it with setLocalState(5), the useCustomHook will immediately return 0 and not 5.
Why doesn't useState return updated value based on if the value passed to it is changed? or why doesn't it have a dependency array like useEffect if we don't want to change its behaviour.
Thanks for your time.
Top comments (8)
I think it's kind of odd example if you call useState in useEffect the component will be caled twice which is normal behavior. Components are not guarantee to be called only once. They can be called multiple times. The most performance issue came from double update the DOM, which will not happen in this case.
Can you show real use case why you would call setState in useEffect?
How would you propose changing state of a hook based on the prop passed to it?
An example would a count-down timer with reset functionality. If we're passing some future time to this custom hook, then the hook needs to update its internal state as well.
You define state inside the hook and return setValue and value from the hook, just like useState does you don't pass state to hook.
yes I think you're right. a hook's state should not depend on its props. it should be private and it should expose functions that trigger hook's state change so that we have more control over hook's state. thanks.
In hooks props are often used for state initialization:
because it happens in different render
when you setLocalState, you update your state to 0 and pass it to the hook, that is one render
useEffect only run at the next render and if there is a change in dependencies, so the first render has to run first (with old value), then it trigger useEffect that set another state and trigger another render, only by that you have the correct value
but i have to say this is a very odd way to update the state, there is pattern that is much better
Thats wierd because you store state in your custom hook, wich isn't good idea. Instead just use outer state, and your problem is solved.
Yes you're right. thank you.