React使用useEffect、useState时首次加载页面数据不渲染问题
问题原因
refreshHandler中的 XMLHttpRequest 是异步操作,你没有等待所有请求返回就提前执行了setCoins。此时请求尚未完成,coin.price还没有被赋值,更新到 state 里的数据没有价格字段,首次渲染自然不显示。点击刷新按钮时能正常显示,是因为上一轮的异步请求已经修改了内存中 coin 对象的属性,这一轮执行setCoins时就带上了之前拿到的价格。- useEffect 不支持直接传入 async 函数,async 函数返回的是 Promise 而非 useEffect 要求的清理函数,会导致React报错,也无法正确等待异步操作执行完成。
- 直接修改 props 传入的
tickerSymbol数组中的对象不符合 React 单向数据流规范,props 是只读属性,直接修改原始引用可能引发不可预期的副作用。 - state 初始化存在逻辑错误:如果
props.tickerSymbol本身是币种数组,useState([props.tickerSymbol])相当于在外面多套了一层数组,虽然你后续在refreshHandler里覆盖了这个错误的初始值,但首次渲染会存在结构不匹配的问题。
修复方案
- 首先调整 state 初始化逻辑,去掉多余的数组嵌套:
const [coins, setCoins] = useState(props.tickerSymbol);
- 将异步请求改为 Promise 封装,等待所有接口请求完成后再统一更新 state,不要直接修改原始 props 对象,而是基于返回结果创建新的对象:
const refreshHandler = async () => { // 遍历所有币种生成请求Promise const requestPromises = coinData.map(async (coin) => { const ApiUrl = `https://api.coingecko.com/api/v3/simple/price?ids=${coin.name}&vs_currencies=usd`; const response = await fetch(ApiUrl); const data = await response.json(); // 不修改原对象,返回新的对象 return { ...coin, price: data[coin.name]?.usd || 0 }; }); // 等待所有请求完成 const newCoins = await Promise.all(requestPromises); // 统一更新state setCoins(newCoins); newCoins.forEach(coin => console.log(coin.price)); };
- 修正 useEffect 的写法,内部定义异步函数再调用:
useEffect(() => { const initData = async () => { await refreshHandler(); }; initData(); }, []);
内容的提问来源于stack exchange,提问作者Drewtang
相关产品推荐
相关产品推荐

