在异步函数中正确使用 useEffect 和 useState [重复]
Posted
技术标签:
【中文标题】在异步函数中正确使用 useEffect 和 useState [重复]【英文标题】:Proper use of useEffect with useState called within async function [duplicate] 【发布时间】:2021-12-20 00:59:14 【问题描述】:致敬!
我正在尝试(并成功)在异步函数中复制一个数组。我正在使用这个数组来设置在 React 组件的顶层声明的数组的状态,如下所示:
const [retrievedData, setRetrievedData] = useState([]);
useEffect(() =>
setRetrievedData;
, [retrievedData]);
async function fetchInfo()
const promiseData = await Promise.all(<My fetch links array>)
);
const dataInJson = await promiseData.map((resp) => resp.json());
let actualData = [];
for (let i = 0; i < dataInJson.length; i++)
const foo = await Promise.resolve(dataInJson[i]);
actualData.push(foo);
setRetrievedData(actualData);
fetchInfo();
这段代码的问题在于它创建了一个无限循环的 setStates,即使我将 useEffect 第二个参数设置为一个空数组也是如此。我还尝试在调用 fetchInfo
函数时使用 async/await,但这当然只是返回另一个 Promise。在处理这个问题时,我还注意到 Promise.all 调用运行了两次。
感谢您花时间阅读此问题。
【问题讨论】:
【参考方案1】:做这样的事情:
const [retrievedData, setRetrievedData] = useState( data: [] );
const fetchInfo = useCallback(async () =>
// do your stuff here...
setRetrievedData( data );
, []);
useEffect(() =>
fetchInfo();
, [fetchInfo]);
如果您打算将数据追加到retrievedData
,那么您可以像这样调用setRetrievedData
:
setRetrievedData(prevState => (
data: [...prevState.data, newData]
));
如果您仅在组件加载期间使用fetchInfo
,您可以将其定义(不带useCallback
)移动到您的useEffect
,并将一个空的依赖数组传递给它,如the other answer 所示。
【讨论】:
这将导致无限循环,因为fetchInfo
是对函数的新引用,useEffect
将在每次调用fetchInfo
时运行,并且每个fetchInfo
将通过设置setState
导致重新渲染跨度>
@Jan 是的,解决了这个问题。请参阅更新后的答案。【参考方案2】:
这是反应中的常见模式
const Component = () =>
const [data, setData] = useState();
useEffect(()=>
const fetchData = async () =>
const data = await fetch();
setData(data);
fetchData();
, [])
return <div>JSON.stringify(data)</div>
【讨论】:
这很好用,谢谢。由于数据是使用状态更新的,所以这不是一个真正的问题,但是这似乎是渲染两次的原因吗?即使我只是在 fetchData 函数中记录数据,我也会先得到 undefined,然后才是想要的结果 第一次组件在没有数据的情况下渲染(例如,您可以显示微调器)之后 useEffect 将运行并调用 fetch 并且当 promise 解决时它将调用 setState 调用 setState 后组件将使用数据更新这次 正常。调用 fetch 后,setData 再次渲染组件 在组件的第一次渲染中,数据未定义,您可以使用显示加载或类似的东西。这是一种常见的模式。这没什么好担心的,因为它不是不必要的渲染。以上是关于在异步函数中正确使用 useEffect 和 useState [重复]的主要内容,如果未能解决你的问题,请参考以下文章
在 useEffect 挂钩中取消所有异步/等待任务以防止反应中的内存泄漏的正确方法是啥?
在useEffect中创建一个异步函数,并在函数的while循环中使用await,似乎不起作用
如何取消 useEffect 清理函数中的所有订阅和异步任务?