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

MERN应用新发布帖子用户名与头像需刷新才显示问题

MERN栈帖子创建后用户名/头像需刷新才显示问题解决

问题描述

我开发了一个MERN栈应用,支持登录用户发布包含文本和图片的帖子。创建帖子后组件会重渲染,帖子自动添加,帖子的图片和文本可正常显示,但用户名和用户头像需刷新页面才能显示。

相关代码

帖子页面(Posts组件)

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getTimeLinePosts } from '../../../actions/postAction';
import Post from '../Post/Post.js';
import PulseLoader from 'react-spinners/FadeLoader';

const Posts = ({ user }) => {
  const dispatch = useDispatch();
  const { posts, loading } = useSelector((state) => state.postReducer);

  console.log('user ID :', user.user._id);
  useEffect(() => {
    dispatch(getTimeLinePosts(user.user._id));
  }, [dispatch, user.user._id]);
  return (
    <div className="Posts">
      {loading ? (
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <PulseLoader
            color="#485639"
            height={15}
            width={5}
            loading={loading}
          />
        </div>
      ) : posts && posts.length ? (
        posts.map((post, i) => <Post key={i} post={post} index={i} />)
      ) : (
        "You haven't shared anything yet."
      )}
    </div>
  );
};

export default Posts;

单个帖子组件(Post组件)

import Moment from 'react-moment';
import { Link } from 'react-router-dom';
import { Dots, Public } from '../../../svg';
import { useRef } from 'react';
import './style.css';
import { useSelector } from 'react-redux';

const Post = ({ post }) => {
  //const { user } = useSelector((state) => state.authReducer.authData);

  return (
    <div className="post">
      <div className="post_header">
        <Link to={`/${post?.user.username}`} className="post_header_left">
          <img src={post?.user.picture} alt="" />
          <div className="header_col">
            <div className="post_profile_name">
              {post?.user.first_name} {post?.user?.last_name}
              <div className="updated_p">
                {post.type === 'profilePicture' &&
                  'updated their profile picture'}
                {post.type === 'cover' && 'updated their cover picture'}
              </div>
            </div>
            <div className="post_profile_privacy_date">
              <Moment fromNow interval={30}>
                {post.createdAt}
              </Moment>
              . <Public color="#828387" />
            </div>
          </div>
        </Link>
        <div className="post_header_right hover1">
          <Dots color="#828387" />
        </div>
      </div>
      <div className="post_text">{post.text}</div>
      {post.images && post.images.length && (
        <div
          className={
            post.images.length === 1
              ? 'grid_1'
              : post.images.length === 2
              ? 'grid_2'
              : post.images.length === 3
              ? 'grid_3'
              : post.images.length === 4
              ? 'grid_4'
              : post.images.length >= 5 && 'grid_5'
          }
        >
          {post.images.slice(0, 5).map((image, i) => (
            <img src={image.url} key={i} alt="" className={`img-${i}`} />
          ))}
          {post.images.length > 5 && (
            <div className="more-pics-shadow">+{post.images.length - 5}</div>
          )}
        </div>
      )}
    </div>
  );
};

export default Post;

postController

exports.getTimelinePosts = async (req, res) => {
  const userId = req.params.id;

  try {
    const posts = await Post.find({ user: userId }).populate(
      'user',
      'username first_name last_name picture'
    );

    res.status(200).json(posts);
  } catch (error) {
    res.status(500).json(error);
  }
};

postRequest函数

export const getTimeLinePosts = (id, token) => async (dispatch) => {
  console.log(id);
  const API_URL = 'api/posts/';
  dispatch({ type: 'RETREIVING_START' });
  try {
    const { data } = await axios.get(API_URL + `${id}/timeline/`);
    dispatch({ type: 'RETREIVING_SUCCESS', data: data });
  } catch (error) {
    dispatch({ type: 'RETREIVING_FAIL' });
    console.log(error);
  }
};

postReducer相关部分

case 'RETREIVING_START':
      return { ...state, loading: true, error: false };
case 'RETREIVING_SUCCESS':
  return {
    ...state,
    posts: action.data.reverse(),
    loading: false,
    error: false,
  };
case 'RETREIVING_FAIL':
  return { ...state, loading: false, error: true };

问题原因

创建帖子时,后端返回的新帖子数据未填充user关联字段(仅包含user ID),前端将这条未填充的数据加入Redux后,Post组件无法读取post.user.username、post.user.picture等信息;而刷新页面时调用getTimeLinePosts接口,后端会通过populate方法填充完整的user信息,因此能正常显示。

解决方法

1. 修改后端创建帖子接口,返回填充后的帖子数据

在创建帖子的controller中,保存帖子后执行populate操作,返回包含完整user信息的帖子:

exports.createPost = async (req, res) => {
  try {
    const newPost = new Post(req.body);
    const savedPost = await newPost.save();
    // 填充user字段,获取需要的用户信息
    const populatedPost = await Post.findById(savedPost._id).populate(
      'user',
      'username first_name last_name picture'
    );
    res.status(200).json(populatedPost);
  } catch (error) {
    res.status(500).json(error);
  }
};

2. 前端创建帖子后,将填充后的新帖子加入Redux

修改创建帖子的action,将后端返回的完整帖子数据添加到Redux的posts数组中:

export const createPost = (postData) => async (dispatch) => {
  try {
    const { data } = await axios.post('/api/posts', postData);
    // 将新帖子插入到posts数组开头,保证最新帖子显示在最前面
    dispatch({ type: 'ADD_POST', payload: data });
  } catch (error) {
    console.log(error);
  }
};

3. 在postReducer中添加处理新帖子的case

// 新增ADD_POST case
case 'ADD_POST':
  return {
    ...state,
    posts: [action.payload, ...state.posts]
  };

这样处理后,创建帖子时前端就能拿到包含完整用户信息的帖子数据,组件渲染时无需刷新即可显示用户名和头像。

内容的提问来源于stack exchange,提问作者Stephen Scott Moore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 03:25:02