React组件更新状态后未重渲染 报未挂载组件更新警告
问题根因
你遇到的两个问题分别来自两个代码缺陷:
- 评论列表不更新:本地
comments状态仅在组件首次挂载时通过传入的post?.comments初始化,后续帖子评论数据更新后,本地状态没有和最新props同步,自然不会触发重渲染。 - 未挂载组件状态更新警告:
handleClick里的dispatch是异步操作,如果请求过程中用户跳转页面导致当前组件被卸载,异步请求完成后依然调用setComments、setComment,就会触发React的内存泄漏警告。
修复步骤
- 引入
useEffect和useRef能力,用ref存储组件挂载状态,组件卸载时标记为不可更新,避免卸载后执行状态更新 - 增加状态同步逻辑,监听props传入的
post.comments变化,实时同步到本地comments状态 - 优化评论列表key值,避免单纯用数组索引作为key引发的渲染异常
- 补充边界值默认判断,避免空数据引发的渲染报错
修复后完整代码
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
相关产品推荐
相关产品推荐

