使用React-Redux通过ID查找数据时返回undefined问题求助
React-Redux博客详情页获取数据问题
问题描述
我正在使用React-Redux开发基础博客CRUD应用,博客列表设有“阅读更多”按钮,点击后跳转对应博客详情页。尝试通过useParams Hook获取博客ID,调用findBlog action从Redux状态的博客列表中查找对应博客。目前能正确获取博客ID,但调用actions.findBlog(id)后,console.log(blog)显示undefined。
相关代码
动作创建器(Actions)
export const listBlog = (blogList) => { return (dispatch) => { dispatch({ type: "list-blog", payload: blogList }) } } export const addBlog = (blog) => { return (dispatch) => { dispatch({ type: "add-blog", payload: blog }) } } export const deleteBlog = (id) => { return (dispatch) => { dispatch({ type: "delete-blog", payload: id }) } } export const findBlog = (id) => { return (dispatch) => { dispatch({ type: "find-blog", payload: id }) } }
reducer - blogReducer
import blogs from "../data" const reducer = (state=blogs, action) => { if (action.type === "list-blog") { return state } else if (action.type === "add-blog"){ state.push(action.payload) return state } else if (action.type === "delete-blog") { state.pop(action.payload) return state } else if (action.type === "find-blog") { for(let i=0; i<=state.length; i++){ if(state[i].id === action.payload){ console.log(state[i]) return state[i] } else{ return "Blog not Found" } } } else { return state } } export default reducer
博客详情页 - BlogPage.js
import React, { useEffect, useState } from "react"; import { useDispatch } from "react-redux"; import { useParams } from "react-router-dom"; import { bindActionCreators } from "redux"; import { actionCreators } from "../State/index"; export const BlogPage = () => { const [blogId, setBlogId] = useState(); const dispatch = useDispatch(); const actions = bindActionCreators(actionCreators, dispatch) const params = useParams() useEffect(() => { setBlogId(params.blogId) },[]) const handleEdit = (id) => { console.log(id) const blog = actions.findBlog(id) console.log(blog) } return ( <div className="container"> <h3></h3> <p> Body </p> <button className="btn btn-success my-3" onClick={() => handleEdit(blogId)}>Edit Blog</button> <button className="btn btn-danger mx-3">Delete Blog</button> <hr className="my-3"/> <button className="btn btn-primary">Like</button> <br /> <br /> <h4 className="mx-3">Comments</h4> </div> ) }
问题原因
- Redux Action调用不返回数据:
actions.findBlog(id)是触发状态更新的dispatch操作,本身不会返回目标博客数据——Redux的工作流是action触发reducer更新状态,组件需要通过useSelector从store中读取更新后的状态。 - Reducer逻辑错误:
find-blog分支的for循环条件i<=state.length会导致数组越界(数组索引最大为state.length-1);- 循环中第一次不匹配就直接返回"Blog not Found",不会继续遍历后续元素;
- 直接返回单个博客或字符串会替换整个Redux状态(原本是数组),破坏状态结构。
- 状态修改不遵循不可变性:
add-blog中用state.push、delete-blog中用state.pop都是直接修改原数组,不符合Redux状态不可变的要求,可能导致状态更新不触发组件重渲染。 - delete-blog逻辑错误:
pop方法不接收参数,只会删除数组最后一个元素,无法根据id删除指定博客。
解决方案
1. 重构Reducer,修正状态结构与逻辑
将状态改为包含博客列表和选中博客的对象,确保状态不可变,修复查找、增删逻辑:
import blogs from "../data" // 初始状态改为对象,包含博客列表和选中的博客 const initialState = { blogList: blogs, selectedBlog: null } const reducer = (state = initialState, action) => { switch(action.type) { case "list-blog": return state; case "add-blog": // 返回新数组,保持不可变性 return { ...state, blogList: [...state.blogList, action.payload] }; case "delete-blog": // 根据id过滤数组,删除指定博客 return { ...state, blogList: state.blogList.filter(blog => blog.id !== action.payload) }; case "find-blog": // 用find方法查找对应id的博客,找不到则返回null const foundBlog = state.blogList.find(blog => blog.id === action.payload) || null; return { ...state, selectedBlog: foundBlog }; default: return state; } } export default reducer
2. 修改组件,正确获取Redux状态
使用useSelector读取选中的博客,移除不必要的state存储blogId:
import React, { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useParams } from "react-router-dom"; import { bindActionCreators } from "redux"; import { actionCreators } from "../State/index"; export const BlogPage = () => { const dispatch = useDispatch(); const actions = bindActionCreators(actionCreators, dispatch); const params = useParams(); // 从Redux状态中获取选中的博客 const selectedBlog = useSelector(state => state.blog.selectedBlog); // 组件挂载时自动查找对应博客 useEffect(() => { if (params.blogId) { actions.findBlog(params.blogId); } }, [params.blogId, actions]); const handleEdit = () => { console.log("选中的博客:", selectedBlog); // 在这里处理编辑逻辑 } return ( <div className="container"> <h3>{selectedBlog ? selectedBlog.title : "加载中..."}</h3> <p> {selectedBlog ? selectedBlog.body : ""} </p> <button className="btn btn-success my-3" onClick={handleEdit}>Edit Blog</button> <button className="btn btn-danger mx-3">Delete Blog</button> <hr className="my-3"/> <button className="btn btn-primary">Like</button> <br /> <br /> <h4 className="mx-3">Comments</h4> </div> ) }
3. 额外优化点
- 移除
bindActionCreators,直接使用dispatch调用action:// 替换bindActionCreators的写法 const findBlog = (id) => dispatch(actionCreators.findBlog(id)); - 如果博客ID是字符串类型,确保与Redux中存储的id类型一致(比如都是字符串或数字),避免匹配失败。
内容的提问来源于stack exchange,提问作者Innomight
相关产品推荐
相关产品推荐

