我知道ref是一个可变的容器,所以它不应该列在useEffect
的依赖项中,但是ref.current
可以是一个不断变化的值。
当ref用于存储像<div ref={ref}>
这样的DOM元素时,以及当我开发依赖于该元素的自定义钩子时,假设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]
);
};
我读过这篇评论说ref应该在useEffect
中使用,但我不知道任何情况下,ref.current
被更改,但效果不会触发。
正如那个问题所建议的,我应该使用回调ref,但是ref as参数对于集成多个钩子非常友好:
const ref = useRef(null);
useFoo(ref);
useBar(ref);
而回调引用更难使用,因为用户被强制组合它们:
const fooRef = useFoo();
const barRef = useBar();
const ref = element => {
fooRef(element);
barRef(element);
};
<div ref={ref} />
这就是为什么我问在useEffect
中使用ref.current
是否安全。
6条答案
按热度按时间2skhul331#
这是不安全的,因为改变引用不会触发渲染,因此,不会触发
useEffect
。React Hook useEffect有一个不必要的依赖:'ref. current'。排除它或删除依赖数组。像'ref.current'这样的可变值不是有效的依赖项,因为改变它们不会重新呈现组件。(react-hooks/exhaustive-deps)
反模式示例:
与此模式相关的一个真实的用例是当我们想要有一个持久引用时,即使元素卸载。
检查下一个例子,当它卸载时,我们不能保持元素大小。我们将尝试使用
useRef
与useEffect
组合如上,但它不会工作。令人惊讶的是,为了解决这个问题,我们需要直接处理
node
,同时使用useCallback
存储函数:useEffect
的用法bkhjykvo2#
2021年答案:
本文解释了将refs与
useEffect
一起使用的问题:Ref objects inside useEffect Hooks:如果将useRef钩子与跳过呈现的useEffect合并,则它可能是自定义钩子的陷阱。您的第一React是将ref.current添加到useEffect的第二个参数中,这样一旦ref更改,它就会更新。但是ref直到你的组件渲染后才会更新-这意味着,任何跳过渲染的useEffect在下一次渲染之前都不会看到ref的任何更改。
同样如本文所述,官方的react文档现在已经更新了推荐的方法(使用回调而不是ref + effect)。请参阅如何测量DOM节点?:
inb24sb23#
我也遇到了同样的问题,我用Typescript创建了一个自定义钩子,用ref callback创建了一个官方方法。希望对大家有所帮助。
lbsnaicq4#
我也遇到过类似的问题,我的ESLint抱怨
useCallback
在useCallback
中的使用。我在我的项目中添加了一个自定义钩子来规避这个eslint警告。每当ref对象更改时,它切换一个变量以强制重新计算useCallback
。*/
function useRefWithCallback<T extends HTMLSpanElement | HTMLDivElement | HTMLParagraphElement>(): [
boolean,
(node: any) => void,
RefObject
] {
const ref = useRef<T | null>(null);
const [toggle, setToggle] = useState(false);
const refCallback = useCallback(node => {
ref.current = node;
setToggle(val => !val);
}, []);
return [toggle, refCallback, ref];
}
export default useRefWithCallback;
yizd12fk5#
我在尝试使用
ResizeObserver
时遇到了这个问题。最后使用回调引用observeRef
,我从执行观察的自定义钩子中传递回来。用它
测试
s71maibg6#
我已经停止使用
useRef
,现在只使用useState
一次或两次:对于图表,auth和其他非react库很有用,因为它保留了一个元素ref和初始化的对象,并且可以根据需要直接处理它。
我现在不知道为什么
useRef
首先存在...?