gpt4 book ai didi

javascript - 来自 React Hook 内部的变量 useEffect 将在每次渲染后丢失

转载 作者:行者123 更新时间:2023-12-05 00:34:41 25 4
gpt4 key购买 nike

我有 here完美运行的文本动画。我现在要添加的是 Intersection Observer,这样动画只有在我向下滚动到 Box 时才会开始。
所以我为实现这一点所做的是:我使用 react 钩子(Hook) useRef 用作对我想要观察的元素的引用,并将其应用到我的 Box 中,其中 ref={containerRef}。然后声明了一个回调函数,它接收一个 IntersectionObserverEntries 数组作为参数,在这个函数中,我采用第一个也是唯一一个条目并检查它是否与视口(viewport)相交,如果是,那么它调用 setIsVisible 并使用 entry.isIntersecting (真假)。之后,我添加了 react 钩子(Hook) useEffect 并使用回调函数和我之前创建的选项创建了一个观察者构造函数。我在一个名为 useElementOnscreen 的新钩子(Hook)中实现了逻辑。
它正在工作,但我收到警告但无法解决:
1.初始代码tsx文件

const useElementOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
const containerRef = useRef<HTMLDivElement | null>(null);
const [isVisible, setIsVisible] = useState(false);

const callbackFunction = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};

useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);

if (containerRef.current) observer.observe(containerRef?.current);

return () => {
if (containerRef.current) observer.unobserve(containerRef?.current);
};
}, [containerRef, options]);

return [containerRef, isVisible];
};

在这里我收到警告: if (containerRef.current) observer.unobserve(containerRef?.current);警告是:
(property) MutableRefObject<HTMLDivElement | null>.current: HTMLDivElement
The ref value 'containerRef.current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy 'containerRef.current' to a variable inside the effect, and use that variable in the cleanup function.
eslint react-hooks/exhaustive-deps
2. 我试图消除警告的方法是将当前的 ref 值保存到一个局部范围的变量中,以便在函数中关闭。
const useElementOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
let observerRefValue: Element | null = null; // <-- variable to hold ref value
const containerRef = useRef<HTMLDivElement | null>(null);
const [isVisible, setIsVisible] = useState(false);

const callbackFunction = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};

useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);

if (containerRef.current) observer.observe(containerRef?.current);
observerRefValue = containerRef.current; // <-- save ref value

return () => {
if (observerRefValue) observer.unobserve(observerRefValue); // <-- use saved value
};
}, [containerRef, options]);

return [containerRef, isVisible];
};
但话又说回来,我收到警告: observerRefValue = containerRef.current; // <-- save ref value
(property) MutableRefObject<HTMLDivElement | null>.current: HTMLDivElement | null
Assignments to the 'observerRefValue' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect.eslintreact-hooks/exhaustive-deps
3. 现在我更改了我的let observerRefValue: Element | null = null;const [observerRefValue, setObserverRefValue] = useState<Element | null>(null);警告消失了,它的工作!
但是在当前状态下,我没有使用 setObserverRefValue在任何地方,我都会收到警告 'setObserverRefValue' is assigned a value but never used .
const useElementOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
const [observerRefValue, setObserverRefValue] = useState<Element | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const [isVisible, setIsVisible] = useState(false);

const callbackFunction = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};

useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);

if (containerRef.current) observer.observe(containerRef?.current);

return () => {
if (observerRefValue) observer.unobserve(observerRefValue); // <-- use saved value
};
}, [observerRefValue, containerRef, options]);

return [containerRef, isVisible];
};
这只是一个警告,但我的问题是:
我的解决方案是否正确处理先前的警告?或者有没有更好的解决方案?
关于 'setObserverRefValue' is assigned a value but never used有没有办法在我的例子中使用它,所以我可以摆脱警告?

最佳答案

亚当发布的内容是解决此问题的好方法。我在我的代码库中使用完全相同的代码模式。 ref 不是钩子(Hook)的一部分,而是作为 Prop 传递的。这样钩子(Hook)只包含检查 Node 的逻辑。 ref 所指向的是否在屏幕上可见。到目前为止,这对我们有用。
现在在您的代码中,钩子(Hook)负责处理 ref也。然后附上 ref钩子(Hook)返回的任何值。 (有兴趣在评论中了解您为什么遵循这种模式。)
我将讨论您提供的所有三个代码片段:

  • 使用效果
  • useEffect(() => {
    const observer = new IntersectionObserver(callbackFunction, options);

    if (containerRef.current) observer.observe(containerRef?.current);
    observerRefValue = containerRef.current; // <-- save ref value

    return () => {
    if (observerRefValue) observer.unobserve(observerRefValue); // <-- use saved value
    };
    }, [containerRef, options]);

    首先,您可以使用 containerRef作为依赖项,但让我提醒您更改 containerRef.current不会触发渲染。它不是 state变量并且不会导致重新渲染。所以如果 ref更改,您无法确定 useEffect回调将再次运行,因此您的 ref 中可能有错误的值。容器。
    linting 警告也有同样的问题:

    The ref value 'containerRef.current' will likely have changed by thetime this effect cleanup function runs. If this ref points to a noderendered by React, copy 'containerRef.current' to a variable insidethe effect, and use that variable in the cleanup function.


    这是 link进行了类似的讨论。此代码 sandbox来自讨论的是一个很棒的演示。
    function Box() {
    const ref = useRef();

    useEffect(() => {
    console.log("mount 1 ", ref.current);
    return () => setTimeout(() => console.log("unmount 1 ", ref.current), 0);
    }, []);

    useEffect(() => {
    const element = ref.current;

    console.log("mount 2 ", element);
    return () => setTimeout(() => console.log("unmount 2 ", element), 0);
    }, []);

    return (
    <div ref={ref} className="box">
    Box
    </div>
    );
    }

    export default function App() {
    let [state, setState] = useState(true);

    useEffect(() => {
    setTimeout(() => setState(false), 1000);
    }, []);

    return (
    <div className="App">
    <p>useEffect useRef warning</p>
    {state && <Box />}
    </div>
    );
    }
    第一个 useEffect 的输出返回函数将是 unmount 1 null , 因为值已经改变了,但是效果回调是不知道的。
    类似的 DOM 操作也可能发生在您的代码中。既然我们承认警告是有道理的,让我们首先找到解决方案:
    简单的解决方案:
    const useOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
    const containerRef = useRef<HTMLDivElement | null>(null);
    const [isVisible, setIsVisible] = useState(false);

    const callbackFunction = (entries: IntersectionObserverEntry[]) => {
    const [entry] = entries;
    setIsVisible(entry.isIntersecting);
    };

    useEffect(() => {
    const observer = new IntersectionObserver(callbackFunction, options);
    const refCopy = containerRef.current;
    if (refCopy) observer.observe(refCopy);

    return () => {
    if (refCopy) observer.unobserve(refCopy);
    };
    }, [options]);

    return [containerRef, isVisible];
    };
    上面的代码解决了所有警告。这正是 linter 所建议的。引用指向 DOM Element ,卸载时为 null ,但是通过保留变量的副本,我们仍然可以访问它并使用它做任何我们想做的事情。
    来到你的其他尝试:
  • observerRefValue在这里是一个非特殊变量(不是 ref 变量也不是 state 变量),对它所做的更改将在每次渲染时被清除。所以你不能依赖它的值(value)。每次重新渲染后,它都会被赋值为 null正如最初定义的那样。因此发出警告。这也可能对您的用例没有帮助。
  • 您在这里创建了一个额外的状态变量。初始化为 null但从未更新为任何其他值。以下条件将始终为假,您的预期代码将不会仅运行:
  • if (observerRefValue)
    这也无助于您的用例。此外,如果不需要,您不应该使用状态变量。

    关于javascript - 来自 React Hook 内部的变量 useEffect 将在每次渲染后丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73085745/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com