![](/img/trans.png)
[英]State Value Stops Updating Within UseEffect Hook - Gatsby/React
[英]State variable inside a function defined within useEffect hook is not updating when value changes
我有一個項目需要測量 DOM 元素的高度,然后在 useState 掛鈎中設置該值,最后在useState
掛鈎中使用useEffect
值。 但是,我在useState
中定義的值(名為maxTranslate
)在 function 中使用。 即使我將maxTranslate
作為依賴項添加到useEffect
, maxTranslate
中的 maxTranslate 的值也不會從其初始值-440
改變。 我可以確認在useEffect
state 更改上觸發了maxTranslate
。
我顯然認為這與陳舊的閉包有關,但由於它正在重新渲染,我不太清楚為什么。 我錯過了什么?
我首先定義一個useState
:
// state variable that defines a default maxTranslate value
const [maxTranslate, setMaxTranslate] = useState(-440)
這里我定義了一個useEffect
接受 3 個 DOM refs 並計算它們的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
function 應該在頁面重新渲染並關閉時重新定義 maxTranslate 的最新值的maxTranslate
,對嗎? 這里發生了什么? 謝謝!
編輯:添加了完整的 useEffect
這里的問題是,由於 maxTranslate 值的變化,當 useEffect 再次運行時,您沒有清理使用 createGesture 創建的先前偵聽器
因此,當您不這樣做時,即使組件不需要那些舊的偵聽器,它們仍然會繼續存在並且不會被垃圾收集,因為它們的引用不會丟失
因此,getStep 方法在為前一個偵聽器觸發時使用舊值調用
它始終建議您在清理 function 的 useEffect 時清除訂閱和聽眾
useEffect(() => {
...
return () => {
swipeGesture.destroy();
}
}, [animationEl, maxTranslate])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.