ReactJS报错:TypeError: 无法读取未定义属性'reduce'问题求助
问题排查与修复
错误根源
控制台报错TypeError: Cannot read properties of undefined (reading 'reduce'),说明**dataKey变量在某一时刻变为了undefined**,而非初始的空数组,导致调用数组方法reduce时触发错误,进而引发页面崩溃空白。
代码中的核心问题
- 接口返回未做校验:
GetData中直接将result.data[1]赋值给dataKey,若接口返回的data数组长度不足2,或result.data[1]本身为undefined,会直接把dataKey从初始空数组改成undefined。 defEndDate的无意义更新:defEndDate在组件每次渲染时都会重新计算(new Date()每次执行生成新对象),导致useEffect的依赖频繁变化,可能触发不必要的接口请求,甚至引发状态异常。- 无空值保护:直接对
dataKey调用reduce,未处理dataKey为undefined的边界情况。
修复方案
1. 给dataKey添加空值保护
在调用reduce前确保dataKey是数组:
const hasil = Object.values( (dataKey || []).reduce((acc, curr) => { // 原reduce逻辑不变 }, {}) );
2. 缓存defEndDate避免无效更新
用useMemo缓存初始结束日期,确保组件渲染时它的值稳定:
const defEndDate = useMemo(() => new Date().toLocaleDateString("en-US"), []);
3. 接口返回校验
在GetData中校验接口返回的result.data[1],避免将undefined赋值给dataKey:
const GetData = async () => { try { const result = await getHitApiTotal(StartDate, EndDate); // 确保赋值的是数组,不存在则设为空数组 setDataKey(Array.isArray(result.data[1]) ? result.data[1] : []); console.log(result.data[1]); } catch (error) { console.log(error); // 出错时也重置为数组,避免后续报错 setDataKey([]); } };
4. 可选:添加加载状态
在接口请求期间显示加载提示,提升用户体验的同时避免渲染错误内容:
const [loading, setLoading] = useState(false); const GetData = async () => { setLoading(true); try { const result = await getHitApiTotal(StartDate, EndDate); setDataKey(Array.isArray(result.data[1]) ? result.data[1] : []); } catch (error) { console.log(error); setDataKey([]); } finally { setLoading(false); } }; // 渲染时判断加载状态 if (loading) return <div>加载中...</div>;
修正后的完整代码片段
import { useState, useEffect, useMemo } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; // 假设startDate、endDate、getHitApiTotal已正确导入 const HitApiChart = () => { const [openModal, setOpenModal] = useState(false); const defEndDate = useMemo(() => new Date().toLocaleDateString("en-US"), []); const StartDate = useRecoilValue(startDate); const EndDate = useRecoilValue(endDate); const setStartDate = useSetRecoilState(startDate); const setEndDate = useSetRecoilState(endDate); const [dataKey, setDataKey] = useState([]); const [loading, setLoading] = useState(false); const GetData = async () => { setLoading(true); try { const result = await getHitApiTotal(StartDate, EndDate); setDataKey(Array.isArray(result.data[1]) ? result.data[1] : []); console.log(result.data[1]); } catch (error) { console.log(error); setDataKey([]); } finally { setLoading(false); } }; const hasil = Object.values( (dataKey || []).reduce((acc, curr) => { const dateStr = curr["@timestamp"].split("T")[0]; if (!acc[dateStr]) { acc[dateStr] = { message: curr.message, timestamp: dateStr, count: 0, }; } acc[dateStr].count++; return acc; }, {}) ); const labels = hasil.map((item) => item.timestamp); const data = { labels, datasets: [ { data: hasil.map((item) => item.count), borderColor: "rgb(255, 99, 132)", backgroundColor: "rgba(255, 99, 132, 0.5)", pointRadius: 6, xAxisID: "x1", }, ], options: { plugins: { legend: { display: false, }, }, }, }; useEffect(() => { if (defEndDate !== EndDate) { GetData(); } }, [EndDate, StartDate, defEndDate]); if (loading) return <div>加载中...</div>; return ( {/* 你的Chart.js组件和日期选择器渲染逻辑 */} ); }; export default HitApiChart;
内容的提问来源于stack exchange,提问作者Kia Kalista
相关产品推荐
相关产品推荐

