如何在 React 中只监听 1 个变量的变化,同时还使用其他变量?

时间:2021-05-03 13:52:28

标签: reactjs react-hooks use-effect

我正在尝试使用函数式 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 发生变化时,不要运行相同的代码。

1 个答案:

答案 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() 的行为没有影响。