gpt4 book ai didi

reactjs - 当 ref 指向 DOM 元素时,使用 ref.current 作为 useEffect 的依赖是否安全?

转载 作者:行者123 更新时间:2023-12-04 09:35:07 27 4
gpt4 key购买 nike

我知道 ref 是一个可变容器,所以它不应该列在 useEffect 中。的依赖项,但是 ref.current可能是一个变化的值。

当使用 ref 存储 DOM 元素时,如 <div ref={ref}> ,当我开发一个依赖该元素的自定义钩子(Hook)时,假设 ref.current如果组件有条件地返回,则可以随时间变化,例如:

const Foo = ({inline}) => {
const ref = useRef(null);
return inline ? <span ref={ref} /> : <div ref={ref} />;
};

我的自定义效果收到 ref 是否安全?反对和使用 ref.current作为依赖?

const useFoo = ref => {
useEffect(
() => {
const element = ref.current;
// Maybe observe the resize of element
},
[ref.current]
);
};

我已阅读 this comment说 ref 应该用在 useEffect ,但我无法弄清楚 ref.current 的任何情况已更改,但不会触发效果。

正如那个问题所建议的,我应该使用回调引用,但是作为参数的引用对于集成多个钩子(Hook)非常友好:

const ref = useRef(null);
useFoo(ref);
useBar(ref);

虽然回调 ref 更难使用,因为用户被强制编写它们:
const fooRef = useFoo();
const barRef = useBar();
const ref = element => {
fooRef(element);
barRef(element);
};

<div ref={ref} />

这就是为什么我要问使用 ref.current 是否安全。在 useEffect .

最佳答案

这是不安全的,因为改变了引用 不会触发渲染 ,因此,不会触发 useEffect .

React Hook useEffect has an unnecessary dependency: 'ref.current'.Either exclude it or remove the dependency array. Mutable values like'ref.current' aren't valid dependencies because mutating them doesn'tre-render the component. (react-hooks/exhaustive-deps)


反模式示例:
const Foo = () => {
const [, render] = useReducer(p => !p, false);
const ref = useRef(0);

const onClickRender = () => {
ref.current += 1;
render();
};

const onClickNoRender = () => {
ref.current += 1;
};

useEffect(() => {
console.log('ref changed');
}, [ref.current]);

return (
<>
<button onClick={onClickRender}>Render</button>
<button onClick={onClickNoRender}>No Render</button>
</>
);
};
Edit xenodochial-snowflake-hhgr6

一个 现实生活用例与此模式相关的是当我们想要一个持久引用时, 即使元素卸载 .
检查下一个示例,在该示例中,当它卸载时我们无法坚持元素大小调整。我们将尝试使用 useRefuseEffect组合如上, 但它不起作用 .
// BAD EXAMPLE, SEE SOLUTION BELOW
const Component = () => {
const ref = useRef();

const [isMounted, toggle] = useReducer((p) => !p, true);
const [elementRect, setElementRect] = useState();

useEffect(() => {
console.log(ref.current);
setElementRect(ref.current?.getBoundingClientRect());
}, [ref.current]);

return (
<>
{isMounted && <div ref={ref}>Example</div>}
<button onClick={toggle}>Toggle</button>
<pre>{JSON.stringify(elementRect, null, 2)}</pre>
</>
);
};
Edit Bad-Example, Ref does not handle unmount

令人惊讶的是,要修复它,我们需要处理 node直接在使用 useCallback 内存函数时:
// GOOD EXAMPLE
const Component = () => {
const [isMounted, toggle] = useReducer((p) => !p, true);
const [elementRect, setElementRect] = useState();

const handleRect = useCallback((node) => {
setElementRect(node?.getBoundingClientRect());
}, []);

return (
<>
{isMounted && <div ref={handleRect}>Example</div>}
<button onClick={toggle}>Toggle</button>
<pre>{JSON.stringify(elementRect, null, 2)}</pre>
</>
);
};
Edit Good example, handle the node directly
  • 请参阅 React Docs 中的另一个示例:How can I measure a DOM node?
  • 进一步阅读和更多示例参见 uses of useEffect
  • 关于reactjs - 当 ref 指向 DOM 元素时,使用 ref.current 作为 useEffect 的依赖是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60476155/

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