我需要在渲染后提供一些使用refs的自定义功能。
对于useEffect
来说,这似乎是一个完美的用例,但它需要在一个自定义钩子中,以便可以重用。
不幸的是,传递一个ref
或它的current
给一个自定义钩子,使用useEffect似乎会导致不同的行为,而不是直接调用useEffect
。
一个工作示例如下:
const useCustomHookWithUseEffect = (el1, el2) => {
React.useEffect(() => {
console.log("CUSTOM Use effect...");
console.log("firstRef element defined", !!el1);
console.log("secondRef element", !!el2);
}, [el1, el2]);
}
const RefDemo = () => {
const [vis, setVis] = React.useState(false);
const firstRef = React.useRef(null);
const secondRef = React.useRef(null);
useCustomHookWithUseEffect(firstRef.current, secondRef.current);
React.useEffect(() => {
console.log("Standard Use effect...");
console.log("firstRef element defined", !!firstRef.current);
console.log("secondRef element ", !!secondRef.current);
}, [firstRef.current, secondRef.current]);
console.log("At RefDemo render", !!firstRef.current , !!secondRef.current);
return (
<div>
<div ref={firstRef}>
My ref is created in the initial render
</div>
<div className="clickme" onClick={() => setVis(true)}>
click me
</div>
{vis &&
<div ref={secondRef}>boo (second ref must surely be valid now?)</div>
}
</div>
)
}
在第一次渲染之后,自定义钩子没有firststref的定义值,但是内联的useEffect有。
单击click-me后,自定义钩子再一次没有获得最近的更新(尽管现在它有了第一个stref值)。
这是预期的吗?
我如何才能实现目标:能够重用地提供使用refs的基于useeffect的代码?
https://jsfiddle.net/GreenAsJade/na1Lstwu/34/
这是控制台日志:
"At RefDemo render", false, false
"CUSTOM Use effect..."
"firstRef element defined", false
"secondRef element", false
"Standard Use effect..."
"firstRef element defined", true
"secondRef element ", false
Now I click the clickme
"At RefDemo render", true, false
"CUSTOM Use effect..."
"firstRef element defined", true
"secondRef element", false
"Standard Use effect..."
"firstRef element defined", true
"secondRef element ", true
问题是您在呈现给自定义钩子时传递了ref.current
。现在,当您更改vis
的状态时,该组件将再次从上到下执行(读取效果,但尚未执行)。但是在这个渲染中,当你调用自定义钩子时,你的ref还没有更新(因为我们还没有真正的重新渲染,所以把ref赋给了第二个div)。因为你特别传递了ref的值,它不会显示实际更新的ref值,而是你在函数调用时传递的值(null)。当效果随后运行时,您只能访问您传递的显式值,而不像您传递ref本身,其值始终是最新的。这个代码沙箱应该能说明这个问题。
我发现我问了两个问题。这是我找到的答案,"我应该如何实现refs
的副作用?">
答案是"不要在useEffect
中使用refs
"。当然,在某些情况下,它可能是好的,但它肯定是自找麻烦。
相反,使用ref回调来实现创建和销毁ref
的副作用。
ref callback
的语义更容易理解:在创建节点时调用一个,在销毁节点时调用另一个。