React Reducer刷新后状态为undefined,首次渲染正常后续操作失效求助
React应用数组操作undefined错误问题
问题描述
我正在开发首个React应用,将服务器返回的数据存入state的空数组中,但操作该数组时抛出undefined错误。首次渲染一切正常,但后续操作均失败。
相关代码
App组件
import { React, useEffect, useContext } from "react"; import { getExchangeCourse } from "./api/currencyApi"; import { ADD_CURRENCY } from "./reducer/currencyReducer"; import { CurrenciesConverterContextComponent } from "./context/Context"; import Header from "./components/Header"; function App() { const [, dispatch] = useContext(CurrenciesConverterContextComponent); useEffect(() => { getExchangeCourse().then(data => dispatch({ type: ADD_CURRENCY, payload: data })) }, []) return ( <div className="App"> <Header /> </div> ); }
Header组件
export default function Header() { const [{currencies}] = useContext(CurrenciesConverterContextComponent); let USD = currencies.find(e => e.cc === "USD"); let EUR = currencies.find(e => e.cc === "EUR"); let GBP = currencies.find(e => e.cc === "GBP"); // 上述方法首次渲染有效,后续操作失败 return ( <div className='converter-header'> <span>{USD.cc} : {USD.rate}</span> <span>{EUR.cc} : {EUR.rate}</span> <span>{GBP.cc} : {GBP.rate}</span> </div> ) }
Reducer
export const initialState = { currencies: [], } export const ADD_CURRENCY = '[CURRENCIES] Add Currency'; export const currenciesReducer = ( state = initialState, action) => { switch(action.type) { case ADD_CURRENCY: return { ...state, // currencies: [...state.currencies, action.payload] currencies: action.payload }; default: { return { ...state } } } }
API请求
import axios from 'axios'; const currencyAPI = axios.create({ baseURL: 'https://bank.gov.ua/NBUStatService/v1/statdirectory/exchange?json', headers: {"Content-type": "application/json"}, }) export async function getExchangeCourse() { const {data} = await currencyAPI.get() console.log(data); return data; }
问题分析
- 未处理空数组/找不到项的情况:初始state中
currencies是空数组,调用find方法会返回undefined;如果后续因组件重新挂载、state意外重置等操作导致currencies回到空数组,直接访问USD.cc这类属性就会抛出Cannot read properties of undefined错误。 - 缺乏状态校验:Reducer中直接将
action.payload赋值给currencies,未校验payload是否为有效数组,若API返回异常数据(非数组),会导致后续数组操作失败。
解决方案
方案1:添加可选链操作符与默认值
修改Header组件中访问属性的代码,避免undefined报错:
export default function Header() { const [{currencies}] = useContext(CurrenciesConverterContextComponent); const USD = currencies.find(e => e.cc === "USD"); const EUR = currencies.find(e => e.cc === "EUR"); const GBP = currencies.find(e => e.cc === "GBP"); return ( <div className='converter-header'> <span>{USD?.cc || 'USD'} : {USD?.rate || '--'}</span> <span>{EUR?.cc || 'EUR'} : {EUR?.rate || '--'}</span> <span>{GBP?.cc || 'GBP'} : {GBP?.rate || '--'}</span> </div> ) }
方案2:条件渲染
在数据未加载完成时显示加载状态,避免渲染未定义的内容:
export default function Header() { const [{currencies}] = useContext(CurrenciesConverterContextComponent); // 数组为空时显示加载提示 if (currencies.length === 0) { return <div className='converter-header'>加载中...</div>; } const USD = currencies.find(e => e.cc === "USD"); const EUR = currencies.find(e => e.cc === "EUR"); const GBP = currencies.find(e => e.cc === "GBP"); return ( <div className='converter-header'> <span>{USD.cc} : {USD.rate}</span> <span>{EUR.cc} : {EUR.rate}</span> <span>{GBP.cc} : {GBP.rate}</span> </div> ) }
方案3:强化Reducer的数据校验
确保currencies始终为数组类型,避免异常数据破坏状态:
export const currenciesReducer = ( state = initialState, action) => { switch(action.type) { case ADD_CURRENCY: // 校验payload是否为数组,不是则保留原状态 const validCurrencies = Array.isArray(action.payload) ? action.payload : state.currencies; return { ...state, currencies: validCurrencies }; default: { return { ...state } } } }
内容的提问来源于stack exchange,提问作者Artem Bilozyorov
相关产品推荐
相关产品推荐

