You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Redux Toolkit实现表单提交后更新评论UI的问题求助

Redux Toolkit 评论提交功能修复指南

一、Redux Toolkit 核心工作流

  1. 触发Action:组件通过useDispatch钩子获取dispatch函数,调用action creator生成action并派发给store。
  2. 更新状态:Slice中的reducer函数接收当前状态和action,直接修改状态(RTK内置Immer库自动处理不可变更新逻辑)。
  3. 订阅渲染:组件通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:00:47