问题
I was trying to implement a simple paint component with React hooks. My expected behavior was 'mouseMove' to be executed when I moved my mouse while remaining clicked. However, state.isMouseDown always returned false within mouseMove().
Any fixes or references to potentially helpful documents would be grateful.
const initialState = {
isMouseDown: false,
isMouseMoving: false
};
const DrawingCanvas = () => {
const [state, setState] = useState(initialState);
useEffect(() => {
console.log('mounted');
document.addEventListener('mousedown', () => mouseDown());
document.addEventListener('mousemove', () => mouseMove());
}, []);
const mouseDown = () => {
console.log('mousedown');
setState(state => ({
...state,
isMouseDown: true
}));
};
const mouseMove = () => {
// why is this false even when click and move?
console.log('mouseMove:isMouseDown', state.isMouseDown);
if (!state.isMouseDown) return;
console.log('mousemove'); // this line is not being executed
setState(state => ({
...state,
isMouseMoving: true
}));
};
console.log(state);
return (
<div>
<p>mouseDown: {`${state.isMouseDown}`}</p>
<p>mouseMoving: {`${state.isMouseMoving}`}</p>
</div>
);
};
回答1:
As explained in this related answer, the problem is that event listener accesses state object from the scope where it was defined, i.e. initial state, because event is listened on component mount.
A solution is to either use mutable state, or access state
exclusively from state updater function. In the code above, state.isMouseDown
refers to original state. In case it's needed to avoid state updates, state updater can return original state:
const mouseMove = () => {
setState(state => {
if (!state.isMouseDown)
return state; // skip state update
else
return {
...state,
isMouseMoving: true
};
});
};
来源:https://stackoverflow.com/questions/55126487/function-not-correctly-reading-updated-state-from-react-hook-state