基于Redux Toolkit实现表单提交后更新评论UI的问题求助
Redux Toolkit 评论提交功能修复指南
一、Redux Toolkit 核心工作流
- 触发Action:组件通过
useDispatch钩子获取dispatch函数,调用action creator生成action并派发给store。 - 更新状态:Slice中的reducer函数接收当前状态和action,直接修改状态(RTK内置Immer库自动处理不可变更新逻辑)。
- 订阅渲染:组件通过
useSelector钩子订阅store中的指定状态,状态变化时自动重新渲染展示最新数据。
二、代码问题排查与修复
1. 修复commentsSlice.js
reducer参数错误且未导出action creator:
import { COMMENTS } from "../../shared/comments"; import { createSlice } from "@reduxjs/toolkit"; const initialState = { comments: COMMENTS, }; export const commentsSlice = createSlice({ name: "comments", initialState, reducers: { addComment: { reducer: (state, action) => { // 移除多余的state默认值,state为slice完整状态对象 state.comments.push(action.payload); // RTK允许直接修改,Immer处理不可变更新 }, prepare: (value) => { return { payload: { ...value, date: new Date().toISOString(), id: Math.random(), }, }; }, }, }, }); // 导出action creator供组件调用 export const { addComment } = commentsSlice.actions; export default commentsSlice.reducer;
2. 修复SubmitComment.js
未接收props、未获取dispatch、表单字段名不匹配:
import { useState } from "react"; import { useDispatch } from "react-redux"; import { addComment } from "./stateSlices/commentsSlice"; import { Button, Modal, ModalHeader, ModalBody } from "reactstrap"; import { useForm } from "react-hook-form"; function SubmitComment({ dishId }) { // 接收dishId props const [modal, setModal] = useState(false); const dispatch = useDispatch(); // 获取dispatch函数 const toggle = () => setModal(!modal); const { register, formState: { errors }, handleSubmit, reset, } = useForm(); const onSubmit = (data) => { const { rating, author, comment } = data; dispatch(addComment({ dishId, rating, author, comment })); reset(); toggle(); // 提交后关闭模态框 }; return ( <> <div> <Button color="primary" onClick={toggle}> Submit </Button> <Modal isOpen={modal} toggle={toggle} fade={false}> <ModalHeader toggle={toggle}>Submit Comment</ModalHeader> <ModalBody> <form onSubmit={handleSubmit(onSubmit)}> <div className="mb-3"> <label htmlFor="rating" className="form-label"> Rating </label> <select name="rating" className="form-select " aria-label="Default select example" {...register("rating", { required: true })} > <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> </div> <div className="mb-3"> <label htmlFor="author" className="form-label"> Your Name </label> <input type="text" className="form-control" id="author" placeholder="Your Name" name="author" // 字段名改为author,匹配data.author {...register("author", { required: true, maxLength: 15 })} /> <small className="form-text text-danger"> {errors.author?.type === "required" && "此字段为必填项"} {errors.author?.type === "maxLength" && "最多允许15个字符"} </small> </div> <div className="mb-3"> <label htmlFor="comment" className="form-label"> Comment </label> <textarea type="text" name="comment" className="form-control" id="comment" aria-describedby="comment" rows="6" {...register("comment", { required: true })} /> </div> <button type="submit" className="btn btn-primary"> Submit </button> </form> </ModalBody> </Modal> </div> </> ); } export default SubmitComment;
3. 修复Dishdetail.js
从store获取评论并过滤当前菜品的评论:
import { useSelector } from "react-redux"; import RenderComments from "./RenderComments"; const Dishdetail = (props) => { const { dish } = props; // 从store获取所有评论,过滤当前菜品的评论 const allComments = useSelector(state => state.comments.comments); const dishComments = dish ? allComments.filter(comment => comment.dishId === dish.id) : []; if (dish != null) { return ( <div className="container "> <div className="row "> <div className="col-12 col-sm-5 col-md-5 m-1"> <RenderComments comments={dishComments} /> </div> </div> </div> ); } else { return <div></div>; } }; export default Dishdetail;
4. 修复RenderComments.js
处理评论为空时的dishId获取问题:
import SubmitComment from "./SubmitComment"; function RenderComments({ comments }) { // 安全获取dishId,避免数组为空报错 const dishId = comments.length > 0 ? comments[0].dishId : null; if (comments.length > 0) { return ( <> <div> {comments.map((comment) => { const options = { year: "numeric", month: "short", day: "2-digit" }; return ( <div key={comment.id}> <ul className="list-unstyled"> <li>{comment.comment}</li> <li> --{comment.author} {new Date(comment.date).toLocaleDateString("en-us", options)} </li> </ul> </div> ); })} {dishId && <SubmitComment dishId={dishId} />} </div> </> ); } else { return ( <div> <p>No comments yet.</p> {dishId && <SubmitComment dishId={dishId} />} </div> ); } } export default RenderComments;
三、关键注意事项
确保根组件被Provider包裹,传入store:
import { Provider } from "react-redux"; import store from "./store"; function App() { return ( <Provider store={store}> {/* 其他组件 */} </Provider> ); }
内容的提问来源于stack exchange,提问作者Prince Singh
相关产品推荐
相关产品推荐

