簡體   English   中英

在 useEffect 掛鈎中定義的 function 中的 State 變量在值更改時不會更新

[英]State variable inside a function defined within useEffect hook is not updating when value changes

我有一個項目需要測量 DOM 元素的高度,然后在 useState 掛鈎中設置該值,最后在useState掛鈎中使用useEffect值。 但是,我在useState中定義的值(名為maxTranslate )在 function 中使用。 即使我將maxTranslate作為依賴項添加到useEffectmaxTranslate中的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM