React Router v6下点击用户头像跳转详情页嵌套属性访问报错
问题分析与修复方案
错误原因
"Cannot read properties of undefined (reading 'name')" 错误的核心诱因:
- 组件初始化时
item为空白对象,直接访问嵌套属性(如item.company.name、item.address.city)会触发链式访问异常 useEffect未监听路由参数id的变化,路由切换时不会重新获取对应用户数据- 未处理找不到匹配用户的场景,
list.find返回undefined后直接赋值给item,后续访问属性必然报错
修复步骤
1. 优化初始状态与渲染判断
将item初始状态设为null,添加加载状态判断,避免未加载完成时访问属性:
// 修改状态初始化 const [item, setItem] = useState(null); // 在组件顶部添加加载判断 if (!item) { return <div className="flex justify-center items-center h-screen">加载中...</div>; }
2. 完善useEffect依赖
将id加入useEffect依赖数组,确保路由参数变化时重新获取数据:
useEffect(() => { getItem(); }, [id]); // 新增id作为依赖
3. 处理用户不存在的情况
在getItem函数中判断是否找到用户,未找到时跳转到首页:
const getItem = () => { const newItem = list.find((value) => value.id === parseInt(id)); if (!newItem) { navigate('/'); return; } setItem(newItem); };
完整修复后的UserDetail.js代码
import React from 'react'; import { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { list } from './Data'; function Profile() { const [item, setItem] = useState(null); const [show, setShow] = useState(false); const { id } = useParams(); const navigate = useNavigate(); useEffect(() => { getItem(); }, [id]); const getItem = () => { const newItem = list.find((value) => value.id === parseInt(id)); if (!newItem) { navigate('/'); return; } setItem(newItem); }; const Logout = () => { navigate('/'); }; if (!item) { return <div className="flex justify-center items-center h-screen">加载中...</div>; } return ( <div> <div className="w-screen h-screen flex gap-10 px-8 pt-3 overflow-x-hidden"> <div className="flex flex-col w-full"> <div className="h-[13vh] w-[100%] border-b border-gray-300"> <div className="flex h-full items-center justify-between"> <div className="capitalize text-[20px] text-gray-500"> <p>profile</p> </div> <div className="relative inline-block text-left mt-5 ml-40" data-headlessui-state> <div> <button className="inline-flex w-full justify-center rounded-md bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm focus:outline-none " id="headlessui-menu-button-:r0:" type="button" aria-haspopup="menu" aria-expanded="false" data-headlessui-state="open" aria-controls="headlessui-menu-items-:r1:" onClick={() => setShow(!show)} > <div className="cursor-pointer flex justify-end gap-3 items-center"> <img className="rounded-full w-[7%]" src={item.profilepicture} alt={item.id} /> <p>{item.name}</p> </div> </button> </div> {show && ( <div className="absolute right-0 z-10 mt-2 w-[20vw] origin-top-right rounded-md bg-white shadow-lg focus:outline-none transform opacity-100 scale-100" aria-labelledby="headlessui-menu-button-:r0:" id="headlessui-menu-items-:r7:" role="menu" tabIndex={0} data-headlessui-state="open" > <div className=" py-1" role="none"> <div className="flex flex-col justify-center items-center gap-1 pb-2 " role="none"> <img className="rounded-full" src={item.profilepicture} alt="" width="50%" role="none"></img> <p role="none">{item.name}</p> <p className="text-[14px] text-gray-400" role="none"> {item.email} </p> <div className="border-t border-gray-300 "> <button className="mt-2 rounded-[20px] px-2 py-1 text-white bg-[#e15b22]" role="none" onClick={Logout}> Sign out </button> </div> </div> </div> </div> )} </div> </div> </div> <div className="block"> <div className="w-full h-full flex mt-5"> <div className="border-r border-gray-300 h-full w-[40%]"> <div className="flex flex-col w-full items-center h-full justify-center"> <img className="rounded-full w-[48%]" src={item.profilepicture} alt="" /> <p className="text-[16px] font-[400] text-gray-800">{item.name}</p> <div className="flex flex-col gap-2 border-b border-gray-300 py-3"> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">Username:</p> <p className="text-[16px] font-[400] text-gray-800">{item.username}</p> </div> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">email:</p> <p className="text-[16px] font-[400] text-gray-800">{item.email}</p> </div> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">phoneNumber:</p> <p className="text-[16px] font-[400] text-gray-800">{item.phone}</p> </div> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">website:</p> <p className="text-[16px] font-[400] text-gray-800">{item.website}</p> </div> </div> <div className="flex flex-col gap-2 py-3"> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">company:</p> <p className="text-[16px] font-[400] text-gray-800">{item.company.name}</p> </div> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">bs:</p> <p className="text-[16px] font-[400] text-gray-800">{item.company.bs}</p> </div> </div> </div> </div> <div className="h-full w-[60%]"> <div className="flex gap-3 items-center justify-center"> <p className="text-[16px] font-[400] text-gray-400">address:</p> <p className="text-[16px] font-[400] text-gray-800">{item.address.city}</p> </div> </div> </div> </div> </div> </div> </div> ); } export default Profile;
内容的提问来源于stack exchange,提问作者me at stackoverflow
相关产品推荐
相关产品推荐

