React使用axios+useEffect请求REST API时空数组导致map报错
问题原因
你观察到的两次控制台输出、首次渲染拿到空数组都是React的正常运行逻辑,不是bug:
- 组件首次挂载时,
useState初始化的data为空数组,此时异步接口请求尚未返回,会触发第一次渲染 - 接口请求完成后调用
setData更新状态,触发组件重渲染,此时data才是接口返回的真实业务数据,控制台会打印第二次结果
不存在数据重复问题,异步状态下的多次渲染是React的固有机制。你遇到的map方法报错,本质是未等数据就绪就执行数组遍历,甚至可能是接口返回非数组类型值覆盖了初始空数组导致的。
解决方案
你在自定义Hook中已经定义了loading状态,直接用这个状态做渲染拦截是成本最低、逻辑最清晰的方案。
方案1:基于loading状态做条件渲染(推荐)
加载阶段先展示占位提示,等数据请求完成后再渲染列表内容,从根源上避免未就绪状态下的方法调用报错。
修改customsite.jsx代码如下:
import React from 'react'; import Modal from './reusable/modal'; import useFetchData from './hooks/useFetchData'; const Customsite = ()=> { const { data, loading, } = useFetchData(); // 加载中直接返回占位内容,不执行后续列表渲染逻辑 if (loading) return <div>数据加载中,请稍候...</div> return( <div> <p>站点列表</p> {/* 到这里时loading已经为false,data已更新为接口返回的真实数据 */} <ul> {data.map(item => <li key={item.id}>{item.siteName}</li>)} </ul> </div> ) } export default Customsite
方案2:增加类型防御兜底
如果不需要单独的加载态,可以在遍历前加类型判断,哪怕data意外变成非数组值也不会触发报错:
return( <div> <p> we here </p> <ul> {/* 仅当data是数组类型时才执行map遍历,否则渲染空 */} {Array.isArray(data) && data.map(item => <li key={item.id}>{item.siteName}</li>)} </ul> </div> )
自定义Hook优化建议
你当前的useFetchData缺少错误状态,也没有对接口返回值做类型校验,建议补充以下逻辑,进一步降低报错概率:
import { useEffect, useState} from 'react'; import http from '../../services/httpservices'; import config from '../../services/config.json'; const useFetchData = () => { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const { data: response } = await http.get(config.apiEndpoint); // 校验返回值类型,非数组时兜底为空数组,避免后续map报错 setData(Array.isArray(response) ? response : []); setError(null); } catch (error) { console.error(error) setError(error); setData([]); // 请求出错时重置data为空数组 } setLoading(false); }; fetchData(); }, []); return { data, loading, error, }; }; export default useFetchData;
注意事项
- 不存在“跳过首次渲染、直接获取真实数据”的实现方式,React函数组件首次渲染是挂载流程的必经环节,所有异步状态都要经过「初始值渲染->异步更新->重渲染」的流程
- 纯空数组
[]调用map不会触发报错,如果你的代码出现相关报错,大概率是接口返回了null/undefined/对象等非数组值,覆盖了初始的空数组,因此类型校验很有必要 - 开发环境下如果开启了React严格模式,控制台可能出现3次及以上打印,属于正常现象,生产环境不会有该问题。
内容的提问来源于stack exchange,提问作者tyrese humphreys
相关产品推荐
相关产品推荐

