React加密货币应用:API数据可打印但无法渲染,map函数报错
问题分析与解决
问题现象
使用React开发加密货币应用时调用免费API获取数据,遇到以下问题:
- Axios请求后,
console.log(response.data)能看到返回的数组,但执行setCoinList(response.data.coins)时,报错Uncaught TypeError: coinList.map is not a function - 初始状态设为空数组,编辑器无语法错误,Coin组件运行正常
- 添加
coinList &&判断后,报错消失,但页面无内容显示,且控制台数组会被打印两次
原代码
function App() { const [coinList, setCoinList] = useState([]); useEffect(() => { const options = { method: "GET", url: "https://openapiv1.coinstats.app/coins", params: { limit: "20" }, headers: { accept: "application/json", "X-API-KEY": MYAPIKEYHERE, }, }; axios .request(options) .then((response) => { setCoinList(response.data.coins); }) .catch((error) => { console.error(error); }); }, []); return ( <div className="container mx-auto mt-8"> {coinList.map((coin) => { return ( <Coin key={coin.rank} name={coin.name} icon={coin.icon} symbol={coin.symbol} volume={coin.volume} price={coin.price} /> ); })} </div> ); }
修改后的代码片段
<div className="container mx-auto mt-8"> {coinList && coinList.map((coin) => { return ( <Coin key={coin.rank} name={coin.name} icon={coin.icon} symbol={coin.symbol} volume={coin.volume} price={coin.price} /> ); })} </div>
原因分析
map is not a function报错:核心原因是coinList不是数组。虽然初始状态是空数组,但请求返回后,response.data.coins可能并非数组——比如API返回的data本身就是数组,不需要额外取coins字段;或者coins字段为null/undefined。- 页面无内容:添加
coinList &&后,若coinList是空数组,&&判断为真但map遍历空数组不会生成任何元素;若response.data.coins是undefined,coinList会被设为undefined,此时coinList &&为假,不会执行map。 - 控制台打印两次:开发环境下React严格模式会触发两次组件渲染和
useEffect执行,属于正常现象,生产环境不会出现。
解决方案
- 确认API返回结构:在
then回调里打印完整的response.data,确认coins字段是否存在且为数组,再针对性赋值:.then((response) => { console.log('API返回数据:', response.data); // 若API返回的data直接是数组,无需取coins字段 // setCoinList(response.data); // 若存在coins字段,先判断是否为数组再赋值 if (Array.isArray(response.data.coins)) { setCoinList(response.data.coins); } else { console.warn('返回的coins不是数组:', response.data.coins); } }) - 更严谨的数组判断:将
coinList &&替换为Array.isArray(coinList),避免非数组类型导致的逻辑问题:{Array.isArray(coinList) && coinList.map((coin) => ( <Coin key={coin.rank} name={coin.name} icon={coin.icon} symbol={coin.symbol} volume={coin.volume} price={coin.price} /> ))} - 添加加载状态:提升用户体验,在数据未加载完成时显示加载提示:
const [isLoading, setIsLoading] = useState(true); // 在useEffect的then和catch回调中都设置setIsLoading(false) useEffect(() => { // ... 原有请求代码 axios.request(options) .then((response) => { // ... 赋值逻辑 setIsLoading(false); }) .catch((error) => { console.error(error); setIsLoading(false); }); }, []); return ( <div className="container mx-auto mt-8"> {isLoading ? <div>加载中...</div> : ( Array.isArray(coinList) && coinList.map((coin) => ( <Coin {...coin} key={coin.rank} /> )) )} </div> )
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

