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

React组件更新状态后未重渲染 报未挂载组件更新警告

问题根因

你遇到的两个问题分别来自两个代码缺陷:

  • 评论列表不更新:本地comments状态仅在组件首次挂载时通过传入的post?.comments初始化,后续帖子评论数据更新后,本地状态没有和最新props同步,自然不会触发重渲染。
  • 未挂载组件状态更新警告:handleClick里的dispatch是异步操作,如果请求过程中用户跳转页面导致当前组件被卸载,异步请求完成后依然调用setComments、setComment,就会触发React的内存泄漏警告。
修复步骤
  1. 引入useEffect和useRef能力,用ref存储组件挂载状态,组件卸载时标记为不可更新,避免卸载后执行状态更新
  2. 增加状态同步逻辑,监听props传入的post.comments变化,实时同步到本地comments状态
  3. 优化评论列表key值,避免单纯用数组索引作为key引发的渲染异常
  4. 补充边界值默认判断,避免空数据引发的渲染报错
修复后完整代码
import React, { useState, useRef, useEffect } from 'react';
import { Typography, TextField, Button } from '@material-ui/core';
import { useDispatch } from 'react-redux';

import useStyles from './styles';
import { commentPost } from '../../redux/reducers/posts';

const CommentSection = ({ post }) => {
    const classes = useStyles();
    const [comments, setComments] = useState(post?.comments || []);
    const [comment, setComment] = useState("");
    const user = JSON.parse(localStorage.getItem('profile'));
    const dispatch = useDispatch();
    // 组件挂载状态标记
    const isMounted = useRef(true);

    // 组件卸载时修改标记,阻止后续无效状态更新
    useEffect(() => {
        isMounted.current = true;
        return () => {
            isMounted.current = false;
        }
    }, []);

    // 同步props中最新的评论数据到本地状态
    useEffect(() => {
        if (post?.comments) {
            setComments(post.comments);
        }
    }, [post?.comments]);

    const handleClick = async () => {
        const finalComment = `${user.result.name}: ${comment}`;
        const newComments = await dispatch(commentPost({ value: finalComment, id: post._id }));
        // 仅当组件仍处于挂载状态时执行状态更新
        if (isMounted.current) {
            setComments(newComments?.payload?.comments || []);
            setComment('');
        }
    };

    return (
        <div>
            <div className={classes.commentsOuterContainer}>
                <div className={classes.commentsInnerContainer}>
                    <Typography gutterBottom variant="h6">Comments</Typography>
                    {comments.map((c, i) => (
                        <Typography key={`${c}-${i}`} gutterBottom variant="subtitle1">
                            {c}
                        </Typography>
                    ))}
                </div>
                {user?.result?.name && (
                    <div style={{ width: '70%' }}>
                        <Typography gutterBottom variant="h6">Write a Comment</Typography>
                        <TextField 
                            fullWidth 
                            minRows={4} 
                            variant="outlined" 
                            label="Comment" 
                            multiline 
                            value={comment} 
                            onChange={(e) => setComment(e.target.value)} 
                        />
                        <Button 
                            style={{marginTop: '10px'}} 
                            fullWidth 
                            disabled={!comment.trim()} 
                            variant="contained" 
                            color="primary" 
                            onClick={handleClick}
                        >
                            Comment
                        </Button>
                    </div>
                )}
            </div>
        </div>
    );
};

export default CommentSection;
额外说明
  • 代码里给comments加了空数组默认值,避免首次加载时post还没拿到数据导致comments.map执行报错
  • 提交按钮的禁用判断加了trim(),避免用户输入全空格时提交无意义的空评论
  • 如果你的Redux中已经存了当前帖子的最新数据,也可以直接通过useSelector从store取最新评论,不用依赖props传入的post数据,逻辑会更简洁。

内容的提问来源于stack exchange,提问作者dro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:48:24