React路由/blogs/:id路径渲染报错,求排查解决思路
/blogs/:id访问时触发Blog组件类型错误 我在React项目中配置了路由,除了指向<BlogSingle />的/blogs/:id路径外,其余路由均正常运行。访问该路径时,会触发<BlogList />组件内部<Blog />组件的未捕获类型错误:Uncaught TypeError: Cannot read properties of undefined (reading 'user')。即使删除<Blog />内的<Link>组件,手动访问该路径仍会报错,疑惑为何该路由会重新渲染<Blog />组件,附上相关代码及错误信息,求排查思路。
路由配置
<Routes> <Route exact path="/" element={ <div> <BlogForm /> <BlogList /> </div> } /> <Route path="/blogs" element={<UserList />} /> <Route path="/users" element={<UserList />} /> <Route path="/users/:id" element={<User />} /> <Route path="/blogs/:id" element={<BlogSingle />} /> </Routes>
BlogList组件代码
import { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { initializeBlogs } from '../reducers/blogReducer' import Blog from './Blog' const BlogList = () => { const dispatch = useDispatch() const user = useSelector(({ login }) => { return login }) useEffect(() => { dispatch(initializeBlogs()) }, [dispatch]) const blogs = useSelector(({ blog }) => { return blog }) return ( <div> {blogs.map((blog) => ( <Blog key={blog.id} user={user} blog={blog}></Blog> ))} </div> ) } export default BlogList
Blog组件代码
import { useState } from 'react' import { useDispatch } from 'react-redux' import { saveLikes, deleteBlog } from '../reducers/blogReducer' import { Link } from 'react-router-dom' const Blog = ({ user, blog }) => { const [visualForm, setVisualForm] = useState(true) const dispatch = useDispatch() const longFormVisible = { display: visualForm ? 'none' : '' } const shortFormVisible = { display: visualForm ? '' : 'none' } const toggleForm = () => { setVisualForm(!visualForm) } const showDelete = blog.user.id.toString() === user[0].id.toString() const blogStyle = { paddingTop: 10, paddingLeft: 2, border: 'solid', borderWidth: 1, marginBottom: 5, } return ( <div> <div style={Object.assign({}, blogStyle, longFormVisible)}> {blog.title} {blog.author} <button type="submit" onClick={toggleForm}> hide </button> <br /> {blog.url} <br /> likes: {blog.likes}{' '} <button type="submit" onClick={() => dispatch(saveLikes(blog))}> like </button> <br /> {blog.user.name} <br /> {showDelete ? ( <button type="submit" onClick={() => dispatch(deleteBlog(blog))}> delete </button> ) : ( '' )} </div> <div style={Object.assign({}, blogStyle, shortFormVisible)}> <Link to={`blogs/${blog.id}`}> {blog.title} {blog.author} </Link> <button type="submit" onClick={toggleForm}> view </button> </div> </div> ) } export default Blog
BlogSingle组件代码
import { useMatch } from 'react-router-dom' import { useEffect } from 'react' import { useSelector, useDispatch } from 'react-redux' import { initializeUsers } from '../reducers/userReducer' import { initializeBlogs } from '../reducers/blogReducer' const BlogSingle = () => { const dispatch = useDispatch() useEffect(() => { dispatch(initializeUsers()) }, [dispatch]) useEffect(() => { dispatch(initializeBlogs()) }, [dispatch]) /*const users = useSelector(({ user }) => { return user })*/ const blogs = useSelector(({ blog }) => { return blog }) const match = useMatch('/blogs/:id') const blog = match ? blogs.find((blog) => blog.id === match.params.id.toString()) : null console.log(match.params.id.toString()) if (!blog) { return null } return ( <div> <h1> {blog.title} {blog.author} </h1> <h2>added blogs</h2> </div> ) } export default BlogSingle
错误信息
Uncaught TypeError: Cannot read properties of undefined (reading 'user')
at Blog (bundle.js:142:27)
at renderWithHooks (bundle.js:36135:22)
at mountIndeterminateComponent (bundle.js:40752:17)
at beginWork (bundle.js:42207:20)
at HTMLUnknownElement.callCallback (bundle.js:24059:18)
at Object.invokeGuardedCallbackDev (bundle.js:24108:20)
at invokeGuardedCallback (bundle.js:24170:35)
at beginWork$1 (bundle.js:47132:11)
at performUnitOfWork (bundle.js:46269:16)
at workLoopSync (bundle.js:46182:9)
排查思路与解决方案
1. 确认BlogList的渲染范围
检查App组件结构,是否在<Routes>组件外部渲染了BlogList?如果是,会导致所有路由页面都会加载BlogList组件,包括/blogs/:id路径。这种情况下,访问该路径时BlogList会被渲染,进而触发Blog组件的错误。
解决:确保BlogList只在对应路由的element内部渲染(当前路由配置的写法是正确的,重点检查App是否有额外的BlogList渲染)。
2. 给Blog组件添加空值检查
错误根源是blog.user为undefined,导致无法读取id属性。在Blog组件中对可能为空的字段添加可选链或条件判断:
// 修改showDelete的判断逻辑 const showDelete = blog?.user?.id && user?.[0]?.id ? blog.user.id.toString() === user[0].id.toString() : false; // 渲染用户名称时添加空值处理 {blog?.user?.name}
3. 检查Redux中博客数据的完整性
查看initializeBlogs action的处理逻辑,确保后端返回的博客数据包含完整的user字段,且在Redux reducer中正确保存了该字段。如果后端返回的博客仅包含userId而不是完整的user对象,需要在获取博客后关联用户数据。
4. 验证BlogSingle的博客匹配逻辑
BlogSingle中使用match.params.id.toString()匹配博客id,检查Redux中博客的id类型是否为字符串。如果博客id是数字类型,需要改为parseInt(match.params.id)进行匹配,避免因类型不匹配导致找不到博客,进而引发后续问题。
内容的提问来源于stack exchange,提问作者hova

