You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

问题分析

  1. 未处理空数组/找不到项的情况:初始state中currencies是空数组,调用find方法会返回undefined;如果后续因组件重新挂载、state意外重置等操作导致currencies回到空数组,直接访问USD.cc这类属性就会抛出Cannot read properties of undefined错误。
  2. 缺乏状态校验: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:20:31