我正在尝试使用函数式 React 来构建我的(爱好)网站。在那里,我多次遇到以下情况:
const [randomData, setRandomData] = useState(true);
const [activePopup, setActivePopup] = useState(1);
useEffect(() => {
...
console.log(randomData);
}, [activePopup])
(为了清楚起见,这是一个虚构的例子)。
我试图实现 useEffect
块内的代码在 activePopup
更改时运行,并且只有在那时,但我还需要访问其他属性和状态。在 VS Code 中,这会导致警告,指出钩子缺少依赖项,应该添加这些依赖项,或者删除依赖项数组。
理论上,我明白为什么 useEffect
想要依赖数组中的所有变量:如果 randomData
改变而 activePopup
没有改变,这个 useEffect
调用将不会运行。但是如果它不是必须的,而且我只需要在打开弹出窗口时访问它呢?
我知道这样的问题通常意味着代码结构不好,但是对于“我想知道/仅在打开弹出窗口时才对变量 X 的值进行处理”之类的情况,老实说,我可以想不出将变量 X 包含在依赖数组中的原因。也许 useEffect
不是处理这个问题的正确方法,我想有些人会建议在打开弹出窗口的同一位置处理使用变量,但考虑到一些上下文的使用,只需监听activePopup
值的更改非常简单易读。
将 randomData
排除在依赖数组之外并忽略警告是否可以?是否有不同的方式来响应变量的变化?我该如何处理这种情况?
简化
如果 activePopup
发生变化 => 用 randomData
做一些事情。
当 randomData
发生变化时,不要运行相同的代码。
答案 0 :(得分:2)
如果没有更多细节,很难给出适用于这种情况的所有可能情况的答案,但要点是否定的,解决任何特定问题都不需要违反详尽的 deps 规则。
最简单的技巧之一是应用 useRef()
以确保不会从过时的闭包中访问 randomData
:
const [randomData, setRandomData] = useState(true);
const [activePopup, setActivePopup] = useState(1);
const randomDataRef = useRef();
useEffect(() => {
randomDataRef.current = randomData;
}, [randomData]);
useEffect(() => {
// log randomData only when activePopup changes
console.log(randomDataRef.current);
}, [activePopup]);
这是有效的,因为调用 useRef()
的返回值不受穷举依赖规则的约束。无论它是否在数组中,行为都不会改变,并且它的引用在设计上永远不会过时。由于 randomDataRef
被 React 记忆,这完全等同于上述内容:
const [randomData, setRandomData] = useState(true);
const [activePopup, setActivePopup] = useState(1);
const randomDataRef = useRef();
useEffect(() => {
randomDataRef.current = randomData;
}, [randomData, randomDataRef]);
// ^~~~~~~~~~~~~
useEffect(() => {
// log randomData only when activePopup changes
console.log(randomDataRef.current);
}, [activePopup, randomDataRef]);
// ^~~~~~~~~~~~~
为了记录,同样的推理适用于为什么 useState()
返回的 setter 和 useReducer()
的 dispatch 函数也不受穷举-deps 规则的约束;它们都由 React 记忆,因此将它们包含在依赖项数组中或从依赖项数组中省略它们对 useEffect()
的行为没有影响。