React组件首次渲染正常刷新后报错,是代码问题还是API限流?
问题根因分析
你遇到的偶发报错核心是两个原因叠加导致的:
- 代码缺少防御性校验:没有对接口返回内容做类型校验,也没有处理请求异常场景
- 存在API限流的可能性:接口正常时返回数组所以运行正常,触发限流时返回非数组的错误响应,直接导致代码崩溃
具体出错逻辑拆解
你当前的代码逻辑存在两个明显漏洞:
- 父组件的
fetch请求没有异常捕获逻辑,也没有校验返回数据格式:
当API触发限流、网络波动或者服务端错误时,接口可能返回非JSON格式内容、或者返回错误对象而非预期的数组,这时候response.json()要么直接抛出异常导致setISLoading和setEvents不执行,要么把错误对象赋值给events状态 - Menu组件直接对传入的
events调用map方法,没有判断是否为数组:当events是错误对象、undefined等非数组类型时,就会抛出map is not a function的报错,这就是你遇到的偶发失败的直接表现
修复方案
1. 父组件添加异常处理和数据校验
修改后的父组件代码如下:
import React,{useState,useEffect} from 'react'; import './App.css'; import Menu from './components/Menu'; function App() { const [isLoading,setIsLoading] = useState(true); // 给events设置初始空数组兜底 const [events,setEvents] = useState([]) // 新增错误状态用于提示用户 const [error, setError] = useState('') const getEvents = async()=>{ try { const response = await fetch('https://allevents.s3.amazonaws.com/tests/categories.json'); // 先判断请求是否成功 if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`) } const eventsData = await response.json() // 校验返回数据是不是数组 if (!Array.isArray(eventsData)) { throw new Error('接口返回数据格式不符合预期') } setEvents(eventsData); setError('') } catch (err) { // 捕获所有异常,设置错误提示 setError(err.message) // 可以在这里加限流判断,如果状态码是429就是触发了流量限制 if (err.message.includes('429')) { setError('触发API流量限制,请稍后再试') } } finally { // 不管成功失败都把加载状态设为false setIsLoading(false); } } useEffect(()=>getEvents(),[]); if (isLoading) return <h1>Loading...</h1> if (error) return <h1>出错了:{error}</h1> return <Menu events = {events}/> } export default App;
2. Menu组件添加参数兜底
修改后的Menu组件代码如下:
import React from 'react' // 给events参数设置默认值为空数组兜底 const Menu = ({events = []}) => { console.log(events); return ( <div> {/* 调用map前再次确认是数组,避免异常 */} {Array.isArray(events) && events.map((event)=>{ return( <div key={event.category}> <h3>{event.category}</h3> </div>) })} </div> ) } export default Menu
限流验证方法
修改代码后如果报错提示是触发API流量限制,请稍后再试,就可以确认是接口有流量限制,否则就是其他请求异常或者代码问题。
内容的提问来源于stack exchange,提问作者Ajay Bains
相关产品推荐
相关产品推荐

