繁体   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