我有一个项目,需要测量DOM元素的高度,然后在useState
挂钩中设置该值,最后在useEffect
挂钩中使用状态值。但是,在函数中使用了我在useState
中定义的值(名为maxTranslate
)。即使我将maxTranslate
作为对useEffect
的依赖关系,函数内maxTranslate
的值也不会从其初始值-440
改变。我可以确认useEffect
的状态更改已触发maxTranslate
。
我显然认为这与过时的关闭有关,但是由于它是重新渲染的,所以我不确定为什么。我想念什么?
我首先定义一个useState
:
// state variable that defines a default maxTranslate value
const [maxTranslate, setMaxTranslate] = useState(-440)
在这里,我定义了一个useEffect
,它接受3个DOM引用并计算其getBoundingClientRect().height
// useEffect to calculate the height of 3 DOM elements
// please let me know if there there's a better semantic way of doing something like this
useEffect(() => {
setMaxTranslate((-1 * ((pageSize?.height || 0) - (previewSize?.height || 0) - (headerSize?.height || 0))))
}, [pageSize, previewSize, headerSize])
接下来,是我的useEffect
将maxTranslate
作为依赖项。我可以在此处console.log
maxTranslate
并确认值正确更新。
// when maxTranslate changes from the useEffect above, the useEffect below will fire again
useEffect(() => {
let started: boolean = false;
let initialStep: number = 0;
const square = Array.from(animationEl.current!.nodes.values())[0];
const swipeGesture = createGesture({
el: square,
gestureName: 'swipeGesture',
direction: 'y',
threshold: 0,
onMove: (ev) => onMove(ev),
onEnd: (ev) => onEnd(ev),
});
swipeGesture.enable(true);
const onMove = (ev: GestureDetail) => {
if (!started) {
setProgressStart({ forceLinearEasing: true });
started = true;
}
setProgressStep({ step: getStep(ev) });
};
const onEnd = (ev: GestureDetail) => {
if (!started) {
return;
}
swipeGesture.enable(false);
const step = getStep(ev);
const shouldComplete = step > 0.25;
setProgressEnd({ playTo: shouldComplete ? 1 : 0, step });
setOnFinish({
callback: () => {
swipeGesture!.enable(true);
setProgressStart(undefined);
setProgressStep(undefined);
setProgressEnd(undefined);
},
opts: { oneTimeCallback: true },
});
initialStep = shouldComplete ? maxTranslate : 0;
started = false;
};
const getStep = (ev: GestureDetail) => {
const delta = initialStep + ev.deltaY;
// THIS VALUE OF maxTranslate DOES NOT CHANGE FROM THE INITIAL VALUE OF -440 THOUGH!
return clamp(0, delta / maxTranslate, 1);
};
}, [animationEl, maxTranslate]);
一旦页面重新呈现并关闭了getStep
的最新值的范围,就应该重新定义我的maxTranslate
函数,对吗?这里发生了什么?谢谢!
编辑:添加了充分使用效果
答案 0 :(得分:1)
这里的问题是,由于maxTranslate值的更改,当useEffect再次运行时,您不清理由createGesture创建的先前的侦听器。
因此,当您不执行此操作时,即使该组件不需要那些旧的侦听器,它们仍然会继续存在并且不会被垃圾回收,因为它们的引用不会丢失
因此,getStep方法在为先前的侦听器触发时使用旧值调用
它总是建议您在useEffect的清理功能中清除订阅和侦听器
useEffect(() => {
...
return () => {
swipeGesture.destroy();
}
}, [animationEl, maxTranslate])