我仍然不停地做出反应,但仍在努力查看我在做什么错。我有一个用于调整面板大小的组件,在边缘的onmousedown上更新状态值,然后为mousemove使用事件处理程序,该事件处理程序使用该值,但是在值更改后似乎没有更新。
这是我的代码:
export default memo(() => {
const [activePoint, setActivePoint] = useState(null); // initial is null
const handleResize = () => {
console.log(activePoint); // is null but should be 'top|bottom|left|right'
};
const resizerMouseDown = (e, point) => {
setActivePoint(point); // setting state as 'top|bottom|left|right'
window.addEventListener('mousemove', handleResize);
window.addEventListener('mouseup', cleanup); // removed for clarity
};
return (
<div className="interfaceResizeHandler">
{resizePoints.map(point => (
<div
key={ point }
className={ `interfaceResizeHandler__resizer interfaceResizeHandler__resizer--${ point }` }
onMouseDown={ e => resizerMouseDown(e, point) }
/>
))}
</div>
);
});
问题出在handleResize
函数上,应该使用最新版本的activePoint
,它是字符串top|left|bottom|right
,而实际上是null
。
答案 0 :(得分:8)
您可以通过设置器功能访问当前状态,因此可以做到:
const handleResize = () => {
setActivePoint(activePoint => {
console.log(activePoint);
return activePoint;
})
};
答案 1 :(得分:4)
const [activePoint, setActivePoint] = useState(null); // initial is null
const handleResize = () => {
setActivePoint(currentActivePoint => { // call set method to get the value
console.log(currentActivePoint);
return currentActivePoint; // set the same value, so nothing will change
// or a different value, depends on your use case
});
};
答案 2 :(得分:3)
[{"id":[1234],"attributes":[{"typeId":[11],"type":["Main"],"date":["2018-01-01"],"attributes":[{"team":["team1"],"values":{"value1":[1],"value2":[999]}},{"team":["team2"],"values":{"value1":[2],"value2":[888]}}]},{"typeId":[12],"type":["Extra"],"date":["2018-01-02"],"attributes":[{"team":["team1"],"values":{"value1":[3],"value2":[1234]}},{"team":["team2"],"values":{"value1":[4],"value2":[9876]}}]}]}]
读取未来值当前,您的问题是您正在读取过去的价值。因此,当您定义useRef
时,它属于该渲染,因此,当您重新渲染事件侦听器时,什么也没有发生,因此它仍从其渲染中读取旧值。
要解决此问题,您应该通过handleResize
使用一个保持更新的引用,以便可以读取当前值。
useRef
答案 3 :(得分:1)
除了敬畏ChrisBrownie55的建议之外,
可以实现自定义钩子,以避免重复此代码,并使用与标准useState
几乎相同的方法来使用此解决方案:
// useReferredState.js
import React from "react";
export default function useReferredState(initialValue) {
const [state, setState] = React.useState(initialValue);
const reference = React.useRef(state);
const setReferredState = value => {
reference.current = value;
setState(value);
};
return [reference, setReferredState];
}
// SomeComponent.js
import React from "react";
const SomeComponent = () => {
const [someValueRef, setSomeValue] = useReferredState();
// console.log(someValueRef.current);
};
答案 4 :(得分:1)
对于使用打字稿的人,可以使用以下功能:
export const useReferredState = <T>(
initialValue: T = undefined
): [T, React.MutableRefObject<T>, React.Dispatch<T>] => {
const [state, setState] = useState<T>(initialValue);
const reference = useRef<T>(state);
const setReferredState = (value) => {
reference.current = value;
setState(value);
};
return [state, reference, setReferredState];
};
并这样称呼它:
const [
recordingState,
recordingStateRef,
setRecordingState,
] = useReferredState<{ test: true }>();
,当您调用setRecordingState
时,它将自动更新参考和状态。
答案 5 :(得分:0)
您可以使用useEffect挂钩,并在每次activePoint更改时初始化事件侦听器。这样,您可以最大程度地减少代码中不必要的引用的使用。
答案 6 :(得分:0)
long x = 5;
var example = x < 0 ? "Not Available" : x;
进行回调除了ChrisBrownie55建议的正确方法之外,您可以使用类似的方法,将eventListener的回调本身使用useRef
而不是useRef
的值,可能更易于维护。
通过这种方式,您不必担心将来要使用的每个useState
都保存在引用中。
只需将useState
保存在引用中并在每个渲染器上更新其值:
handleResize
,并使用const hanleResizeRef = useRef(handleResize)
hanleResizeRef.current = handleResize;
作为回调,并包装在箭头函数中:
hanleResizeRef
window.addEventListener('mousemove', e => handleResizeRef.current(e));