当值更改时,useEffect挂钩中定义的函数内的状态变量不会更新

时间:2020-05-21 17:57:30

标签: javascript reactjs react-hooks

我有一个项目,需要测量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])

接下来,是我的useEffectmaxTranslate作为依赖项。我可以在此处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函数,对吗?这里发生了什么?谢谢!


编辑:添加了充分使用效果

1 个答案:

答案 0 :(得分:1)

这里的问题是,由于maxTranslate值的更改,当useEffect再次运行时,您不清理由createGesture创建的先前的侦听器

因此,当您不执行此操作时,即使该组件不需要那些旧的侦听器,它们仍然会继续存在并且不会被垃圾回收,因为它们的引用不会丢失

因此,getStep方法在为先前的侦听器触发时使用旧值调用

它总是建议您在useEffect的清理功能中清除订阅和侦听器

useEffect(() => {
   ...
   return () => {
        swipeGesture.destroy();
   }

}, [animationEl, maxTranslate])