A game screen keeps a running score and a separate sound toggle. Accumulating points and changing the sound setting are independent actions that should not interfere with each other.
Click Score +10 several times to build up a score, then click the Sound toggle. The score immediately drops back to zero.
The child's effect fires when it detects a change in one of its dependencies - consider what constitutes a change for a value that is a function.
The child's effect fires when it detects a change in one of its dependencies - consider what constitutes a change for a value that is a function.
Why this fixes it
Every time `GameScreen` re-renders, `const handleComplete = () => {}` allocates a brand-new function at a new memory address. Because `ScoreBoard`'s `useEffect` lists `onComplete` as a dependency, it fires whenever that reference changes - which is on every parent re-render, including the one caused by the sound toggle. Each re-run calls `setScore(0)`, wiping the accumulated score. Wrapping the callback in `useCallback(() => { ... }, [])` memoizes the function so the same reference is returned on every render, and the effect only runs on mount, leaving the score untouched by any unrelated parent state change.