skip to Main Content

I can’t see <PostWidget/> in the UI for below code.

PostsWidget.jsx

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setPosts } from "../../../Redux/Slices/authSlice";
import PostWidget from "../PostWidget";
import { userRequest } from "../../../requestMethod";

const PostsWidget = ({ userId, isProfile = false }) => {
  const dispatch = useDispatch();
  const posts = useSelector((state) => state.posts);
  console.log("posts", posts);

  const getPosts = async () => {
    const res = await userRequest.get("/posts");
    console.log("all Posts", res.data);
    dispatch(setPosts(res.data));
  };

  const getUserPosts = async () => {
    const res = await userRequest.get(`/${userId}/posts`);
    console.log("user Post", res.data);
    dispatch(setPosts(res.data));
  };

  useEffect(() => {
    if (isProfile) {
      getUserPosts();
    } else {
      getPosts();
    }
  }, []);

  return (
    <>
      {posts && posts.map(
        ({
          _id,
          userId,
          firstName,
          lastName,
          description,
          location,
          picturePath,
          userPicturePath,
          likes,
          comments,
        }) => (
          <PostWidget
            key={_id}
            postId={_id}
            postUserId={userId}
            name={`${firstName} ${lastName}`}
            description={description}
            location={location}
            picturePath={picturePath}
            userPicturePath={userPicturePath}
            likes={likes}
            comments={comments}
          />
        )
      )}
    </>
  );
};

export default PostsWidget;

PostWidget.jsx

const PostWidget = () => {
  return (
    <div>
      <h4>Post Widget</h4>
    </div>
  );
};

export default PostWidget;

Here,
userRequest is an axios method. I wrote two functions getPosts and getUserPosts to call the API

AuthSlice.js

import { createSlice } from "@reduxjs/toolkit";
const initialState = {
  mode: "light",
  user: null,
  token: null,
  posts: [],
};      
export const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {                 
 setPosts: (state, action) => {
      state.posts = action.payload.posts;
    },
    setPost: (state, action) => {
      const updatedPosts = state.posts.map((post) => {
        if (post._id ===action.payload.post._id) {
          return action.payload.post;
        }
        return post;
      });
      state.posts = updatedPosts;
    },
  },
});

I checked the console.logs and also redux state with the redux devtool. Both are showing upadated posts.
console.log

all Posts (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]

2

Answers


  1. You will have to return the component in the map method.

    PostsWidget.jsx

    import { useEffect } from "react";
    import { useDispatch, useSelector } from "react-redux";
    import { setPosts } from "../../../Redux/Slices/authSlice";
    import PostWidget from "../PostWidget";
    import { userRequest } from "../../../requestMethod";
    
    const PostsWidget = ({ userId, isProfile = false }) => {
      const dispatch = useDispatch();
      const posts = useSelector((state) => state.posts);
      console.log("posts", posts);
    
      const getPosts = async () => {
        const res = await userRequest.get("/posts");
        console.log("all Posts", res.data);
        dispatch(setPosts(res.data));
      };
    
      const getUserPosts = async () => {
        const res = await userRequest.get(`/${userId}/posts`);
        console.log("user Post", res.data);
        dispatch(setPosts(res.data));
      };
    
      useEffect(() => {
        if (isProfile) {
          getUserPosts();
        } else {
          getPosts();
        }
      }, []);
    
      return (
        <>
          {posts && posts.map(
            ({
              _id,
              userId,
              firstName,
              lastName,
              description,
              location,
              picturePath,
              userPicturePath,
              likes,
              comments,
            }) => (
              return <PostWidget
                key={_id}
                postId={_id}
                postUserId={userId}
                name={`${firstName} ${lastName}`}
                description={description}
                location={location}
                picturePath={picturePath}
                userPicturePath={userPicturePath}
                likes={likes}
                comments={comments}
              />
            )
          )}
        </>
      );
    };
    
    export default PostsWidget;
    
    
    Login or Signup to reply.
  2. Note I found when researching Redux (https://redux-toolkit.js.org/usage/immer-reducers):

    There are several reasons why you must not mutate state in Redux: It causes bugs, such as the UI not updating properly to show the latest values. It makes it harder to understand why and how the state has been updated. It makes it harder to write tests.

    I believe your issue is caused by the setPosts reducer. The state is an object and when you update a property, specifically the posts property via the setPosts dispatch, the object reference is still the same.

    The AuthSlice.js should look like this:

    import { createSlice } from "@reduxjs/toolkit";
    
    const initialState = {
      mode: "light",
      user: null,
      token: null,
      posts: [],
    };
    export const authSlice = createSlice({
      name: "auth",
      initialState,
      reducers: {
        setPosts: (state, action) => {
          const updatedState = {
            ...state,
            posts: action.payload.posts,
          };
    
          return updatedState;
        },
    
        // Make sure to update other reducers to follow suit.
        ...
      },
    });
    

    This should tell the useSelector to re-render the page and grab the new state.posts value.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search