为什么在 useEffect 的依赖数组中需要 history
why history is needed in dependency array of useEffect
在下面的示例中,我使用 history
重定向了一些 link。
const history = useHistory()
useEffect(() => {
history.push(`/my/link`)
}, [])
然后 React 抱怨缺少依赖项 history
。我不明白为什么 history
可以成为这里的依赖项。它不是 state
变量或来自 props
。
如果我将history
添加到依赖数组中,会不会导致无限调用useEffect
。因为 history
在 history.push(
/my/link)
发生时发生了变化。
const history = useHistory()
useEffect(() => {
history.push(`/my/link`)
}, [history])
我的理解对吗?
有很多事情需要澄清。
首先,抱怨的不是 React,而是 ESlint。具体来说,从 eslint-plugin-react-hooks
which you always can disable 规则 react-hooks/exhaustive-deps
但在这样做之前,我们最好确保它是唯一的选择。
其次,不,history
也不一样。在引擎盖下 useHistory
指的是浏览器的 History API and object it returns stays referentially the same. So no, there would be no rerender loop. Yes, React Router wrapper around it returns the same object that will mutate on future navigation 所以它也适用于它。
也很可能在导航到不同的地址时,您的应用程序会转到配置的不同路由,并且该组件消失,被不同的组件集替换。因此,即使 history
在引用上不同(无论如何都不是这种情况),它也不会重新呈现。
最后,ESlint 不理解变量的含义并且它们保持不变,也不是你正在导航的事实。它所做的唯一一件事 - 确保在回调主体中使用并在组件树内声明的所有变量都列在依赖项中。就这样。
在您的特定情况下,您可以将其添加到依赖项中或在每行的基础上禁用特定的 ESlint 规则。我建议您采用第一种方法 - 尽可能少地禁用规则可读性更好。每次禁用规则时都会产生“为什么禁用它?”的问题。稍后,也是潜在问题的根源。
虽然 history
不是直接的状态变量(从您的组件的角度来看)也不是 prop,但它是钩子的输出,因此很可能在钩子内保持状态。此外,详尽的依赖规则不仅适用于 state 和 prop 变量,还适用于任何值可能发生变化的变量。
如果你想避免无限重新渲染,你可以把 history.push
放在你的依赖数组中或者只是从 history
中取出 push
并直接使用它并把 push
在依赖数组中。示例:
const history = useHistory();
React.useEffect(() => {
history.push("/my/link");
}, [history.push]);
const { push } = useHistory();
React.useEffect(() => {
push("/my/link");
}, [push]);
或者,对于这个特定示例,您可以考虑使用 <Redirect>
组件而不是 history.push
。
在下面的示例中,我使用 history
重定向了一些 link。
const history = useHistory()
useEffect(() => {
history.push(`/my/link`)
}, [])
然后 React 抱怨缺少依赖项 history
。我不明白为什么 history
可以成为这里的依赖项。它不是 state
变量或来自 props
。
如果我将history
添加到依赖数组中,会不会导致无限调用useEffect
。因为 history
在 history.push(
/my/link)
发生时发生了变化。
const history = useHistory()
useEffect(() => {
history.push(`/my/link`)
}, [history])
我的理解对吗?
有很多事情需要澄清。
首先,抱怨的不是 React,而是 ESlint。具体来说,从 eslint-plugin-react-hooks
which you always can disable 规则 react-hooks/exhaustive-deps
但在这样做之前,我们最好确保它是唯一的选择。
其次,不,history
也不一样。在引擎盖下 useHistory
指的是浏览器的 History API and object it returns stays referentially the same. So no, there would be no rerender loop. Yes, React Router wrapper around it returns the same object that will mutate on future navigation 所以它也适用于它。
也很可能在导航到不同的地址时,您的应用程序会转到配置的不同路由,并且该组件消失,被不同的组件集替换。因此,即使 history
在引用上不同(无论如何都不是这种情况),它也不会重新呈现。
最后,ESlint 不理解变量的含义并且它们保持不变,也不是你正在导航的事实。它所做的唯一一件事 - 确保在回调主体中使用并在组件树内声明的所有变量都列在依赖项中。就这样。
在您的特定情况下,您可以将其添加到依赖项中或在每行的基础上禁用特定的 ESlint 规则。我建议您采用第一种方法 - 尽可能少地禁用规则可读性更好。每次禁用规则时都会产生“为什么禁用它?”的问题。稍后,也是潜在问题的根源。
虽然 history
不是直接的状态变量(从您的组件的角度来看)也不是 prop,但它是钩子的输出,因此很可能在钩子内保持状态。此外,详尽的依赖规则不仅适用于 state 和 prop 变量,还适用于任何值可能发生变化的变量。
如果你想避免无限重新渲染,你可以把 history.push
放在你的依赖数组中或者只是从 history
中取出 push
并直接使用它并把 push
在依赖数组中。示例:
const history = useHistory();
React.useEffect(() => {
history.push("/my/link");
}, [history.push]);
const { push } = useHistory();
React.useEffect(() => {
push("/my/link");
}, [push]);
或者,对于这个特定示例,您可以考虑使用 <Redirect>
组件而不是 history.push
。