React报错TypeError: 无法读取undefined的'userName'属性原因及解决办法
错误原因分析
- 初始状态类型不匹配:你给
blog设置的初始值是数组[],但服务端返回的是对象结构。初始状态下访问blog.blogTitle返回undefined,React渲染undefined属于合法行为不会抛出错误;但访问blog.owner时,数组不存在该属性返回undefined,再访问undefined.userName就会触发TypeError。 - 加载状态赋值时机错误:你把
setDataMounted(true)写在了异步请求的外侧,组件挂载后不等接口返回数据就会立即执行,直接标记数据加载完成,导致渲染逻辑提前访问还没被赋值的嵌套属性。 - 评论状态更新逻辑错误:直接对
blogComments执行push操作属于直接修改state,不会触发组件重渲染,评论列表更新不会生效。
解决方法
- 修正blog初始值:将初始值改为带有兜底结构的对象,避免嵌套访问报错
// 修改前 const [blog, setBlog] = useState([]) // 修改后 const [blog, setBlog] = useState({ owner: {} })
- 调整加载状态赋值时机:把
setDataMounted(true)移到接口请求的回调内部,确保拿到数据后再标记加载完成,同时把路由参数加入useEffect依赖数组,避免参数变化时不重新请求数据
useEffect(() => { APIService.getBlogById(props.match.params.id).then(response => { setBlog(response.data) setBlogComments([]) // 拿到数据后再标记加载完成 setDataMounted(true) if (!response.data.comments.includes(null)) { response.data.comments.forEach(commentId => { APIService.getCommentById(commentId).then(comment => { // 不要直接push,用不可变方式更新state setBlogComments(prev => [...prev, comment.data]) }) }) } }) // 把路由参数加入依赖数组 }, [props.match.params.id])
- 嵌套属性访问加可选链兜底:访问多层嵌套属性时使用可选链运算符,属性不存在时直接返回
undefined不会抛出错误
// 修改前 <p className='blog-owner'>Created By {blog.owner.userName}</p> // 修改后 <p className='blog-owner'>Created By {blog?.owner?.userName}</p>
内容的提问来源于stack exchange,提问作者Bhavishya
相关产品推荐
相关产品推荐

