Search code examples
reactjsmern

User name and picture don't show up on new post until page refresh


I have a MERN app that allows logged in user to create posts, with text and images. When the post is created the component re-renders and the post is adde automatically. The images and text from the post show up right but the username and user's picture don't show up unless I refresh the page.

This is the posts page:

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;

Here is the individual post component:

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;

Here is the 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);
  }
};

This is the postRequest function:

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);
  }
};

Here is the post request part of the 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 };

Solution

  • I got this answer from another user but then his post was deleted and his profile suspended for a few days. I watied to see if his post would show up, but it has not, so here is the answer. On the posts.js page in the userEffect, I added post?.length and that fiexd the issue.

    useEffect(() => {
        dispatch(getTimeLinePosts(userId));
    }, [dispatch, userId, posts?.length]);
    

    Now when I create a post the user's name and image show up.