我有以下代码:
function App() {
const [appData, setAppData] = useState(initialAppDataValue);
const [test, setTest] = useState("");
// outside useEffect
if(!DataProviderService.isInitialized){
fetchData();
}
// inside useEffect
/*useEffect(() => {
fetchData();
}, []);*/
function fetchData(){
DataProviderService.getAppData().then((data) => {
setAppData(data);
setTest("abc");
});
}
return (<div>something...</div>);
}
字符串
如果我在useEffect外部调用'fetchData',则状态的更新不起作用,但如果我在useEffect内部调用,则工作正常。
我的问题是为什么?在useEffect之外,我更新了状态,然后我看到re-render被调用了,但是值不包含新值。我不明白为什么。
3条答案
按热度按时间aelbi1ox1#
看起来你想要显示的数据是你想要在挂载时获取的数据,而不是在用户交互期间更改的数据(至少就这个组件所知)。因此,据我所知,所需的行为是:
1.组件安装
1.获取数据
1.状态更改以反映返回的数据
1.只要组件已安装,状态就保持在此处
如果你的页面是交互式的,并且在初始挂载后触发了状态更改/重新呈现,那么fetch请求将处理状态更改。然而这会产生不希望的后果,因为它会在每次重新呈现时被调用,但这也是不希望的!
以这种方式在useEffect之外调用fetch请求是不正常的,并且忽略了react生命周期。请记住,每次组件重新呈现和JSX编译时,它都会逐行检查组件并执行您告诉它执行的每个函数。在这种情况下,fetch请求将存在于一个vacum中,并且每次重新呈现时都会被调用。渲染时不考虑或关心当前或先前的状态是什么导致了无限的重新渲染循环。
useEffect将在组件初始渲染后运行,从而知道初始状态以及它与组件中元素的关系。这不仅会导致您想要的结果,其中fetch请求将在初始挂载时调用,而且您可以使用依赖数组告诉react“在挂载时渲染此内容,然后不再渲染”或“在x时渲染此内容,y或z状态变化或功能称为”
TLDR:因为我更像是一个视觉化的人,所以我整理了一个diagram来解释生命周期中发生的事情。
tcomlyy62#
在此代码中,fetchData在组件渲染时被调用。第一次渲染时,DataProviderService未初始化,fetchData未被调用。之后,没有状态或属性更改,组件不会再次重新渲染,fetchData也不会被调用。
ruarlubt3#
当您将fetchData放入带有空[]的useEffect中时,它可以确保在组件首次显示时只执行一次fetchData(...)part正在做一些工作,需要时间才能完成。但是现在,因为fetchData在useEffect内部,它不会在组件呈现时立即运行。useEffect捕获组件第一次显示在屏幕上的时间。它等待异步工作(DataProviderService.getAppData().then(...))来完成,然后再继续。异步工作完成后,使用setAppData和setTest更新状态。这会触发重新呈现,但现在重新呈现发生在异步任务完成后。因此,当组件重新呈现时,它会显示更新后的正确信息。*