React TypeError报错求助:Cannot read properties of undefined (reading '0')
React Grade组件渲染TypeError问题解决
报错信息
Grade.jsx:52 Uncaught TypeError: Cannot read properties of undefined (reading '0') at Grade.jsx:52:1 at Array.map (<anonymous>) at Grade (Grade.jsx:39:1) at renderWithHooks (react-dom.development.js:16305:1) at mountIndeterminateComponent (react-dom.development.js:20074:1) at beginWork (react-dom.development.js:21587:1) at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1) at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1) at invokeGuardedCallback (react-dom.development.js:4277:1) at beginWork$1 (react-dom.development.js:27451:1) (anonymous) @ Grade.jsx:52 Grade @ Grade.jsx:39 renderWithHooks @ react-dom.development.js:16305 mountIndeterminateComponent @ react-dom.development.js:20074 beginWork @ react-dom.development.js:21587 callCallback @ react-dom.development.js:4164 invokeGuardedCallbackDev @ react-dom.development.js:4213 invokeGuardedCallback @ react-dom.development.js:4277 beginWork$1 @ react-dom.development.js:27451 performUnitOfWork @ react-dom.development.js:26557 workLoopSync @ react-dom.development.js:26466 renderRootSync @ react-dom.development.js:26434 recoverFromConcurrentError @ react-dom.development.js:25850 performSyncWorkOnRoot @ react-dom.development.js:26096 flushSyncCallbacks @ react-dom.development.js:12042 (anonymous) @ react-dom.development.js:25651 react-dom.development.js:18687 The above error occurred in the <Grade> component: at Grade (http://localhost:3000/static/js/bundle.js:6687:56) at RenderedRoute (http://localhost:3000/static/js/bundle.js:277704:5) at Outlet (http://localhost:3000/static/js/bundle.js:278056:26) at div at StudentProfileLayout (http://localhost:3000/static/js/bundle.js:6946:72) at RenderedRoute (http://localhost:3000/static/js/bundle.js:277704:5) at Routes (http://localhost:3000/static/js/bundle.js:278141:5) at Routing at App (http://localhost:3000/static/js/bundle.js:349:78) at Router (http://localhost:3000/static/js/bundle.js:278079:15) at BrowserRouter (http://localhost:3000/static/js/bundle.js:276396:5) Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
问题现象
- 渲染前注释成绩列代码
{item.gd?.grades[0]?.grade},组件可正常渲染其他列 - 渲染完成后取消注释,成绩列能正常显示
- 不注释直接渲染触发上述TypeError报错
后端返回数据
ayne abreham alemayehu new ObjectId("63efb168503e390f0b7c986a") new ObjectId("63efb168503e390f0b7c986a") [ { gd: { _id: new ObjectId("63f16c7f03e5a86d748ab2c4"), batch: 1, department: 'None', stream: 'None', subject: 'b', class: new ObjectId("63efb168503e390f0b7c986a"), grades: [Array], createdAt: 2023-02-19T00:25:35.272Z, updatedAt: 2023-02-19T00:25:35.272Z, __v: 0 }, sem: 1 }, { gd: { _id: new ObjectId("63f16c8903e5a86d748ab2c9"), batch: 1, department: 'None', stream: 'None', subject: 'd', class: new ObjectId("63efb168503e390f0b7c986a"), grades: [Array], createdAt: 2023-02-19T00:25:45.106Z, updatedAt: 2023-02-19T00:25:45.106Z, __v: 0 }, sem: 1 sem: 1 } sem: 1 } ]
后端路由代码
router.route("/find/grades").post(async (req, res) => { try { const { fullName } = req.body; const user = await User.findOne({ fullName }); console.log(fullName); const grades = await Grade.find({ department: user.department, stream: user.stream, batch: user.batch, "grades.studentId": user._id, }); const updatedGrades = await Promise.all( grades.map(async (gd, i) => { console.log(gd.class); const sem = await Class.findById({ _id: gd.class }); return { gd, sem: sem.semester }; }) ); console.log(updatedGrades); res.json({ updatedGrades }); } catch (err) { console.log(err); } });
Grade组件代码
import { useState, useEffect, useContext } from "react"; import axios from "axios"; import { UserContext } from "../App.jsx"; function Grade() { const { state, dispatch } = useContext(UserContext); const [data, setData] = useState([{ gd: {}, sem: 1 }]); useEffect(() => { const fetchData = async () => { try { const res = await axios.post("http://localhost:5000/user/find/grades", { fullName: state.name, }); const newData = res.data.updatedGrades.map((item) => ({ gd: item.gd, sem: item.sem })); console.log(newData); setData(newData); } catch (err) { console.log(err); } }; fetchData(); }, []); console.log(data); return ( <div className="w-full text-center"> {console.log(data)} <table className="table-auto lg:table-fixed w-full"> <thead> <tr className="bg-gray-800 text-white"> <th className="lg:w-52 px-4 py-2">Batch</th> <th className="px-4 py-2">Department</th> <th className="px-4 py-2">Stream</th> <th className="px-4 py-2">Semester</th> <th className="px-4 py-2">Subject</th> <th className="px-4 py-2">Grade</th> </tr> </thead> <tbody> {data && data.length > 0 && data.map((item, index) => ( <tr key={index} className="text-gray-700"> <td className="border px-2 py-px">{item.gd.batch}</td> <td className="text-center border px-0.5 py-px"> {item.gd.department} </td> <td className="border px-1.5 py-px">{item.gd.stream}</td> <td className="border px-2 py-px">{item.sem}</td> <td className="text-center border px-2 py-px"> {item.gd.subject} </td> <td className="text-center border px-2 py-px"> {item.gd?.grades[0]?.grade} </td> </tr> ))} </tbody> </table> </div> ); } export default Grade;
问题原因与解决方案
原因
组件第一次渲染时使用初始state:[{ gd: {}, sem: 1 }],其中gd是空对象,没有grades属性。此时执行item.gd?.grades[0]?.grade时,item.gd?.grades返回undefined,继续访问索引0就会触发报错。接口数据返回后data更新,grades存在,所以后续取消注释能正常显示。
解决方案
可采用以下任意一种或多种方式解决:
完善可选链判断
将成绩列代码修改为:{item.gd?.grades?.[0]?.grade}给
grades也加上可选链,确保grades不存在时不会继续访问索引0。优化初始state
初始化state时给gd添加空数组grades,避免第一次渲染时grades属性缺失:const [data, setData] = useState([{ gd: { grades: [] }, sem: 1 }]);增加渲染前的条件判断
在渲染成绩列前先检查grades是否存在且有数据:<td className="text-center border px-2 py-px"> {item.gd?.grades && item.gd.grades.length > 0 ? item.gd.grades[0].grade : '-'} </td>
内容的提问来源于stack exchange,提问作者ayex
相关产品推荐
相关产品推荐

