为什么钩子中的函数依赖项不会导致无限渲染



以下是代码沙盒的代码片段链接:

// function getFetchUrl(query) {
//   return "https://hn.algolia.com/api/v1/search?query=" + query;
// }
function App() {
const [reactResult, setReactResult] = useState(null);
const [reduxResult, setReduxResult] = useState(null);
function SearchResults() {
// 🔴 Re-triggers all effects on every render
// const getFetchUrl = useCallback((query) =>  {
// return "https://hn.algolia.com/api/v1/search?query=" + query;
// }, []);

function getFetchUrl(query) {
return "https://hn.algolia.com/api/v1/search?query=" + query;
}
useEffect(() => {
console.log("running effect: 15");
setReactResult(getFetchUrl("react"));
// ... Fetch data and do something ...
// }, [getFetchUrl]); // 🚧 Deps are correct but they change too often
}, [getFetchUrl]);
useEffect(() => {
console.log("running effect: 21");
setReduxResult(getFetchUrl("redux"));
// ... Fetch data and do something ...
// }, [getFetchUrl]); // 🚧 Deps are correct but they change too often
}, [getFetchUrl]);
// ...
}
SearchResults();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>{reactResult}</h2>
<h2>{reduxResult}</h2>
</div>
);
}

控制台中的输出为

running effect: 15
running effect: 21
running effect: 15
running effect: 21

我已经检查了这个答案,我得到的是重新定义了函数,这导致useEffect再次运行(第二次)。但我想澄清一个疑问:

useEffect第二次运行时,它会调用stateSetter函数(要求 React 再次渲染组件)。

那么上面的代码片段不应该在无限循环中运行吗?

示例和基本理解摘自使用效果完整指南

当使用useState反应足够聪明,可以跳过重新渲染,如果状态值 尽管调用了setState函数,但实际上并没有改变。(这记录在 https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update)

您包含的示例代码与链接的代码笔略有不同,实际上只会生成单个"集"控制台日志消息。

running effect: 15
running effect: 21

事件的顺序是:

  1. 初始渲染会触发效果并更新reactResultreduxResult状态。这会将重新渲染排队。
  2. 组件将重新呈现。在您包含的示例中,您使用的是没有依赖项的useCallback,它将返回以前的值,因此效果将不会运行。

另一方面,在代码笔中,不是useCallback重新定义每次执行时的回调,在这种情况下,您将获得两"组"控制台消息:

  1. 初始渲染会触发效果并更新reactResultreduxResult状态。这会将重新渲染排队。
  2. 组件将重新呈现。getFetchUrl是本地函数,因此等于上一次运行的getFetchUrl。因此,效果将重新运行。但是,setReactResultsetReduxResult都使用与以前相同的值调用,因此不会触发重新渲染。

您的效果仅在getFetchUrl更改时触发...由于它是一个记忆回调(不会更改),因此效果只运行一次。

相关内容

  • 没有找到相关文章