React中API处理类异步调用下表单数据无法显示的问题
异步操作未等待导致React组件无法渲染API数据的解决方案
问题核心
你遇到的问题是异步操作未正确等待,导致组件在数据还未处理完成时就调用了setStat,此时user_opening_percentages还是初始值;而当你修改代码触发热重载时,类实例已经完成了数据处理,所以能显示数据。另外,ChessGameFetcher内部属性的变化不会触发React组件重新渲染,必须确保在异步流程完成后,通过setState传递最新数据。
具体问题点
fetchOpenings函数中创建ChessGameFetcher实例后,没有调用异步的init()方法,直接获取user_opening_percentages,此时数据还未加载和处理。- 即使调用了
init(),也没有等待它完成就执行setStat,导致拿到的是初始空数据。
修复方案
步骤1:修改ChessGameFetcher的init方法,返回处理后的数据
让init方法返回最终的user_opening_percentages,确保异步流程完成后能拿到最新数据:
async init(): Promise<PercentageInfo[]> { await this.fetchGameArchives(); this.logOpenings(); this.returnOpeningData(); this.getPercentages(); return this.user_opening_percentages; // 返回处理好的数据 }
步骤2:修改组件中的fetchOpenings函数,等待异步操作完成
在fetchOpenings中调用init()并等待其完成,再设置状态:
async function fetchOpenings() { setLoading(true); // 开启加载状态 try { const gameFetcher = new ChessGameFetcher(username); // 等待init异步操作完成,拿到处理好的数据 const openingStats = await gameFetcher.init(); console.log(openingStats); setStat(openingStats); // 此时数据已准备好,设置状态触发渲染 } catch (err) { console.error("获取数据失败:", err); } finally { setLoading(false); // 关闭加载状态 } }
步骤3:优化组件渲染逻辑
添加loading状态的显示,同时确保列表基于最新的stat状态渲染:
function OpeningForm() { const [stat, setStat] = useState<PercentageInfo[]>([]); // 初始化为空数组更合理 const [username, setUsername] = useState(""); const [loading, setLoading] = useState(false); const [submitted, setSubmitted] = useState(false); async function fetchOpenings() { setLoading(true); try { const gameFetcher = new ChessGameFetcher(username); const openingStats = await gameFetcher.init(); setStat(openingStats); } catch (err) { console.error("获取数据失败:", err); } finally { setLoading(false); } } const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setSubmitted(true); fetchOpenings(); }; return ( <> <form onSubmit={handleSubmit}> <label> 输入用户名: <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} /> </label> <button type="submit" disabled={loading}> {loading ? "加载中..." : "提交"} </button> </form> {loading ? ( <p>加载数据中...</p> ) : submitted ? ( stat.length > 0 ? ( <ul> {stat.map((st, index) => ( <li key={index}>{st.toString()}</li> ))} </ul> ) : ( <p>暂无数据</p> ) ) : null} </> ); }
额外优化建议
- 避免在组件中直接依赖类实例的内部状态,尽量通过异步方法返回数据,确保数据流清晰。
- 给
stat的初始值设置为空数组,比默认的PercentageInfo实例更符合实际场景,避免渲染无意义的初始数据。 - 添加错误处理,防止API请求失败导致组件异常。
内容的提问来源于stack exchange,提问作者AnthraxFlavouredWax
相关产品推荐
相关产品推荐

