以下是代码段link to codesandbox:
// 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
我已经签出了this的答案,并且得到了重新定义函数的信息,这导致useEffect
再次运行(第二次)。但我想澄清一个疑问:
当useEffect
第二次运行时,它调用stateSetter
函数(要求React再次渲染组件)。
所以上面的代码段不应该无限循环运行吗?
示例和基本理解摘自A Complete Guide to useEffect
答案 0 :(得分:3)
在使用useState
时,如果状态值足够高,react非常聪明,可以跳过重新渲染
尽管调用了setState
函数,实际上并没有改变。 (记录在https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update中)
您所包含的示例代码与链接的代码笔略有不同,实际上只会导致控制台记录消息的单个“集合”。
running effect: 15
running effect: 21
事件的顺序是:
reactResult
和reduxResult
状态。这样就可以重新渲染。useCallback
,没有依赖性,该依赖性将返回先前的值,因此效果将无法运行。另一方面,在您的代码笔中,您无需在每次执行时重新定义回调,而无需useCallback
,在这种情况下,您将获得两套“控制台”控制台消息:
reactResult
和reduxResult
状态。这样就可以重新渲染。getFetchUrl
是本地功能,因此上次运行的不等于getFetchUrl
。结果,效果将重新运行。但是setReactResult
和setReduxResult
的调用值都与以前相同,因此将不触发重新渲染。答案 1 :(得分:0)
仅当getFetchUrl
发生更改时才会触发您的效果……并且由于它是一个已记录的回调(不会更改),因此效果仅运行一次。