React页面刷新后报错:无法读取null的reduce属性问题求助
问题:页面刷新后reduce调用报错,无法计算金额总和
当前代码首次运行正常,但页面刷新后抛出错误:Uncaught TypeError: Cannot read properties of null (reading 'reduce'),报错位置在Balance.js第27行。核心需求是计算fetch返回数组中所有元素amount字段的总和并在组件中展示。
相关代码
Balance.js
import { useEffect } from "react"; import {useBalancesContext} from '../hooks/useBalancesContext' import { useAuthContext } from '../hooks/useAuthContext' function Balance(){ const {balances, dispatch} = useBalancesContext() const {user} = useAuthContext() useEffect(() => { const addBalances = async () => { const response = await fetch("http://localhost:4000/api/balances", { headers: { 'Authorization': `Bearer ${user.token}` } }); const json = await response.json(); if (response.ok) { dispatch({type: 'SET_BALANCES', payload: json}) } } if (user) { addBalances(); } }, [dispatch, user]); const newBalance = balances.reduce((accumulator, currentValue) => accumulator + currentValue.amount, 0) return ( <div className="header"> <strong>Available Balance: ${newBalance}</strong> </div> ) } export default Balance;
BalanceContext.js
import { createContext, useReducer } from "react"; export const BalancesContext = createContext(); export const balancesReducer = (state, action) => { switch (action.type) { case 'SET_BALANCES': return { balances: action.payload } /* case 'SUM_BALANCES': return { balances: state.balances.amount.reduce((accumulator, currentValue) => accumulator + currentValue.amount, 0) } */ case 'CREATE_BALANCE': return { balances: [action.payload, ...state.balances] } case 'DELETE_BALANCE': return { balances: state.balances.filter((b) => b._id !== action.payload._id) } default: return state } } export const BalancesContextProvider = ({ children }) => { const [state, dispatch] = useReducer(balancesReducer, { balances: null }) return ( <BalancesContext.Provider value={{...state, dispatch}}> {children} </BalancesContext.Provider> ) };
解决方案
1. 修正初始状态类型
报错根源是组件初始化时balances为null,刷新后fetch请求完成前,null调用reduce会触发类型错误。将BalanceContext中的初始状态改为空数组:
// BalanceContext.js中修改初始化部分 const [state, dispatch] = useReducer(balancesReducer, { balances: [] // 替换原来的null })
空数组调用reduce会正常返回初始值0,不会报错。
2. 可选:添加加载状态处理
如果需要在数据加载完成前显示友好提示,可在Balance组件中增加判断:
function Balance(){ const {balances, dispatch} = useBalancesContext() const {user} = useAuthContext() useEffect(() => { // 原有代码不变 }, [dispatch, user]); // 数据未加载完成时显示默认值或加载提示 if (balances.length === 0) { return <div className="header"><strong>Available Balance: $0</strong></div> } const newBalance = balances.reduce((accumulator, currentValue) => accumulator + currentValue.amount, 0) return ( <div className="header"> <strong>Available Balance: ${newBalance}</strong> </div> ) }
3. 优化总和计算性能(可选)
使用useMemo缓存计算结果,避免组件每次渲染都重复执行reduce:
import { useEffect, useMemo } from "react"; // 其他代码不变 const newBalance = useMemo(() => { return balances.reduce((accumulator, currentValue) => accumulator + currentValue.amount, 0) }, [balances]) // 仅当balances变化时重新计算
关于reducer计算总和的思路说明
不建议在reducer中用总和替换原始的balances数组,这会丢失原始数据,导致后续无法基于原数组做明细展示、删除等操作。总和属于衍生数据,直接在组件中基于原始数组计算是更合理的方案。
内容的提问来源于stack exchange,提问作者Michael Presson
相关产品推荐
相关产品推荐

