React中API请求等待时渲染多个加载提示的实现方法
解决React多名言加载提示的问题
问题根源
你当前的代码逻辑是等API返回名言数据后,才把数据添加到quotes数组,所以QuoteItem组件从一开始拿到的就是完整的名言数据,根本没机会显示"Loading..."。要实现点击按钮先出加载框、再替换成名言的效果,得先把「加载状态的项」加到列表里,等请求完成后再更新这个项的内容。
具体修改方案
1. 修改QuotesLogic.jsx:区分加载/完成状态的列表项
给每个列表项增加状态标识,点击按钮时先插入一个「加载中」的项,请求完成后再替换成真实名言数据:
import React, { useState, useEffect } from 'react'; import QuoteList from './QuoteList'; // 生成唯一ID,避免用index当key的问题 const generateId = () => Math.random().toString(36).slice(2, 10); export default function QuotesLogic() { const [quotes, setQuotes] = useState([]); useEffect(() => { fetchQuote(); }, []); const fetchQuote = async () => { // 1. 先添加一个加载状态的项 const loadingId = generateId(); setQuotes(prev => [...prev, { id: loadingId, loading: true }]); try { // 2. 请求API const response = await fetch('https://api.quotable.io/random'); const data = await response.json(); await new Promise((resolve) => setTimeout(resolve, 1000)); // 测试用延迟 // 3. 替换加载项为真实名言 setQuotes(prev => prev.map(item => item.id === loadingId ? { id: loadingId, loading: false, data } : item )); } catch (err) { // 处理请求失败的情况,比如替换成错误提示 setQuotes(prev => prev.map(item => item.id === loadingId ? { id: loadingId, loading: false, error: '加载失败' } : item )); } }; return ( <section> <button onClick={fetchQuote}>Generate new</button> <QuoteList quotes={quotes} /> </section> ); }
2. 修改QuoteItem.jsx:根据传入的状态渲染内容
不再用组件内部的loading状态,直接读取父组件传入的列表项状态:
import React from 'react'; export default function QuoteItem({ item }) { if (item.loading) { return ( <div className='border border-green-500'> <p>Loading...</p> </div> ); } if (item.error) { return ( <div className='border border-red-500'> <p>{item.error}</p> </div> ); } const quote = item.data; return ( <div className='border border-green-500'> <p>{quote.content}</p> <p className='text-right'>{quote.author}</p> <p>insert other quote attributes</p> </div> ); }
3. 调整QuoteList.jsx:传递正确的属性并使用唯一key
import React from 'react'; import QuoteItem from './QuoteItem'; export default function QuoteList({ quotes }) { return ( <div> {quotes.map((item) => ( <QuoteItem key={item.id} item={item} /> ))} </div> ); }
效果说明
现在连续点击按钮时,每点击一次就会立刻添加一个显示"Loading..."的框,等API响应完成后,对应的加载框会自动替换成真实的名言内容。即使多次点击,每个加载状态的项都会独立等待自己的API请求完成,不会互相干扰。
内容的提问来源于stack exchange,提问作者Imaginary
相关产品推荐
相关产品推荐

