使用useState异步更新引发Web应用无限重渲染的解决方法
解决React组件无限重渲染与异步数据获取问题
问题根源
你直接在组件函数体内调用setPosts,组件每次渲染时都会执行这段代码:状态更新触发组件重新渲染,重新渲染后又会再次调用setPosts,形成无限循环。
同时你的getPost函数存在疏漏:没有返回创建的Promise对象,导致await getPost无法正确等待异步请求完成,最终getPosts返回的结果不符合预期。
修复步骤
1. 使用useEffect包裹数据获取逻辑
引入useEffect,将数据获取和状态更新放在useEffect回调中,并设置合适的依赖项,确保只在组件挂载(或依赖变化)时执行一次。
修改后的App.jsx代码:
import React, { useState, useEffect } from 'react'; import './App.css'; import Nav from './Navbar/NavBar.jsx'; import Content from "./content/Content" import { getPosts } from "./api/post"; function App() { const idList = ["631a58c165b3a10ac71497e1", "631a58fa65b3a10ac71497e3"]; const [posts, setPosts] = useState([]); useEffect(() => { // 定义异步函数处理数据获取 const fetchPosts = async () => { try { const fetchedPosts = await getPosts(idList); setPosts(fetchedPosts); } catch (err) { console.error('获取文章失败:', err.message); } }; fetchPosts(); }, [idList]); // 依赖项:仅当idList变化时重新执行 return ( <div> {posts.length > 0 ? posts.map(post => <div key={post._id}>{post.title}</div>) : '加载中...'} </div> ); } export default App;
2. 修复getPost函数的Promise返回问题
修改getPost函数,让它返回创建的Promise对象,确保await能正常等待异步请求完成:
import axios from "axios"; const getPost = (id) => { // 返回Promise对象 return new Promise((resolve, reject) => { const url = "/posts/" + id; console.log(url); axios.get(url) .then(response => { if (response.status === 200){ console.log("Succesfull call"); console.log(response.data); resolve(response.data); } else if(response.status === 404){ reject(response); } }) .catch(err => { console.log("Failed call"); reject(err); }); }); }; const getPosts = async (idList) => { var result = []; // 用for...of替代for...in,避免遍历数组索引属性 for(const id of idList){ try{ let post = await getPost(id); result.push(post); }catch(err){ console.log(err.message); } } if (result.length === 0) throw {message: "No posts"}; else return result; }; export {getPosts};
额外优化点
- 用
for...of替代for...in遍历数组,避免意外遍历到数组的原型链属性或索引键。 - 在
useEffect中添加错误捕获,避免请求失败导致组件报错。
内容的提问来源于stack exchange,提问作者Bot Ellis
相关产品推荐
相关产品推荐

