React Hooks调用API后如何实现多条数据立即同步显示
问题根因
- 状态更新未返回新引用:直接修改原有数组的内部属性后返回原数组,React浅比较检测不到状态变化,不会触发重渲染,是点击第二次才显示的核心原因。
- 异步逻辑未统一收口:单独监听每个请求返回更新状态,就算渲染正常也会出现逐行显示的情况,无法实现两行同时出现。
- 代码存在遗漏定义:
useDataApi中未定义setID方法,且初始状态的用户对象缺少steamId字段,会导致请求参数异常。 - 闭包捕获旧状态:在自定义Hook顶层定义
stateCopy,异步方法中捕获的永远是初始化时的旧数组,导致状态更新逻辑异常。
修复方案
核心改动逻辑:
- 去掉闭包中的
stateCopy,所有状态更新都生成全新的数组对象,保证React能检测到状态变化 - 用
Promise.all等待所有异步请求完成后,统一生成新状态一次更新,实现两行数据同时渲染 - 补全缺失的
setID方法和初始字段
修复后代码
index.js(无改动)
import React from "react"; import ReactDOM from "react-dom"; import App from "./test"; ReactDOM.render(<App />, document.getElementById("root"));
app.js
import React, { useState } from "react"; const useDataApi = (initialState) => { const [state, setState] = useState(initialState); // 补全修改steamId的方法 const setID = (number, value) => { setState(prev => { const newState = [...prev]; newState[number] = {...newState[number], steamId: value}; return newState; }) } const getFetch = async (id) => { if (!id) return {Date: ''}; const requestID = await fetch(`https://api.covid19api.com/summary`); return await requestID.json(); }; const setInfo = async () => { // 等待所有请求完成 const resultList = await Promise.all( state.map(item => getFetch(item.steamId)) ) // 生成全新的状态数组 const newState = state.map((item, index) => { return {...item, date: resultList[index].Date || ''} }) // 统一更新状态 setState(newState) }; return { state, setInfo, setID }; }; const Children = ({ data }) => { return ( <ul> {data.map((item) => ( <li key={item.id}> {item.date ? item.date : "Not data"} <br/> </li> ))} </ul> ); }; const InfoUsers = ({ number, steamid, change }) => { return ( <input value={steamid || ''} numb={number} onChange={(e) => change(number, e.target.value)} /> ); }; function App() { // 初始状态补全steamId字段 const usersProfiles = [ { date: "", id: 1, steamId: "" }, { date: "", id: 2, steamId: "" } ]; const profiles = useDataApi(usersProfiles); return ( <div> <InfoUsers number={0} steamid={profiles.state[0].steamId} change={profiles.setID} /> <InfoUsers number={1} steamid={profiles.state[1].steamId} change={profiles.setID} /> <button onClick={() => profiles.setInfo()}>Get</button> <Children data={profiles.state} /> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

