Posts not showing up in order in my MERN stack app (using Redux toolkit)

Viewed 40

I am making a MERN stack app (Social media app) using redux toolkit as the state management system. My problem is even though my redux state changes in my dev tool according to the order that I want it in ( createdAt latest ), it is not represented in my UI.

Here is my code in the server side.

Post Model


import mongoose from "mongoose";

const { Schema } = mongoose;

const requiredNumber = {
  type: Number,
  required: [true,'Please add a longitude and latitude'],
};

const postSchema = new Schema(
  {

    
    userId: { type: String, required: true },

    title: {
      type: String,
      // required: [true,'Please add a title'],
    },
    description:{
        type: String,
        required: [true,'Please add a description']
    },
    
    image: [{
      type: String,
    }],
    
    latitude: {
      ...requiredNumber, //required
      min: -90,
      max: 90,
    },
    longitude: {
      ...requiredNumber, //required
      min: -180,
      max: 180,
    },
    visitDate: {
      // required: [true,'Please add a visit date'],
      type: Date,
    },
    airline:{
      type: String,
    },

    //
    // name: {
    //   type: String,
    // },
    // avatar: {
    //   type: String,
    // },

    // Likes ,comments & date of
    likes: {
      type: Array,
      default: [],
    },
    comments: [{
       type: Schema.Types.ObjectId,
       ref: 'Comment'
    }],

    date: {
      type: Date,
      default: Date.now,
    },

    shares:{
      type: Array,
      default: [],
    },

    // a post may or maynot be a shared post
    // sharedPost:{
    //   type: Schema.Types.ObjectId,
    //   // required: true,
    //   ref: "Post",
    // }

  },
  //---------------------
  {
    timestamps: true,
  }
);

// We registered the model with mongoose
var PostModel = mongoose.model("Posts", postSchema);

export default PostModel;

Here is my PostController

export const getTimelinePosts = async(req,res) =>{
    try {

    const userId = req.params.id;
    const currentUser = await UserModel.findById(userId);
    const userPosts = await PostModel.find({ userId: userId });

    const friendPosts = await Promise.all(
      currentUser.following.map((friendId) => {
        return PostModel.find({ userId : friendId });
      })
    );

    res.status(200).json(userPosts.concat(...friendPosts).sort((a,b)=>{
          return b.createdAt - a.createdAt; //ordered
      }))

    } catch (err) {
        res.status(500)
        throw new Error(err)
    }

}

I have a route in my PostRoute

router.get("/:id/timeline", getTimelinePosts)

On the client side I have a postService in my feature folder (redux) which hits the route using axios and returns the data(posts).

// Get timeline posts for user
// @route   GET /posts/id/timeline
const getTimelinePosts = async (userData) => {

  
  const response = await axios.get(API_URL + `${id}/timeline`)
  

  return response.data
}

This is how I have my slice set up.

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import postService from './postService'

const timelinePosts = []



const initialState = {
  user: user ? user : null,
  timelinePosts: timelinePosts ? timelinePosts : null,
  isError: false,
  isSuccess: false,
  isLoading: false,
  message: '',
}

// Get timeline posts for user
export const getTimeLinePosts = createAsyncThunk(
    'post/timelinePosts',
    async ( _ , thunkAPI) => {

      try {

      const user = thunkAPI.getState().auth.user // getting user from auth state
      return await postService.getTimelinePosts(user)

      
    } catch (error) {

      const message =
        (error.response &&
          error.response.data &&
          error.response.data.message) ||
        error.message ||
        error.toString()

      return thunkAPI.rejectWithValue(message)
      
    }
  }
)

// Create post
export const createPost = createAsyncThunk(
    'post/createPost',
    async (postData, thunkAPI) => {

      try {
      
      const token = thunkAPI.getState().auth.user.token

      return await postService.createPost(postData,token)

      
    } catch (error) {

      const message =
        (error.response &&
          error.response.data &&
          error.response.data.message) ||
        error.message ||
        error.toString()

      return thunkAPI.rejectWithValue(message)
      
    }
  }
)


In my extra reducer:

// getTimeLinePosts
      .addCase(getTimeLinePosts.pending, (state) => {
        state.isLoading = true
      })
      .addCase(getTimeLinePosts.fulfilled, (state, action) => {
        state.isLoading = false
        state.isSuccess = true
    
        state.timelinePosts = action.payload
        
        
      })
      .addCase(getTimeLinePosts.rejected, (state, action) => {
        state.isLoading = false
        state.isError = true
        state.message = action.payload
        state.timelinePosts = null
      })

// createPost
      .addCase(createPost.pending, (state) => {
        state.isLoading = true
      })
      .addCase(createPost.fulfilled, (state, action) => {
        state.isLoading = false
        state.isSuccess = true
        

        state.timelinePosts = [action.payload, ...state.timelinePosts] 
        
        
      })
      .addCase(createPost.rejected, (state, action) => {
        state.isLoading = false
        state.isError = true
        state.message = action.payload
      })

Even though initially after loading my posts show up in the order intended, after creating a post the order does not persist and my new created post shows up at the bottom of the feed.

Here is the AllPosts (post generator which feeds my timeline)


import { useSelector, useDispatch } from "react-redux";
import { getTimeLinePosts,createPost } from '../features/post/postSlice';

import { useEffect } from "react";



const AllPosts = () => {

  // redux 
  const dispatch = useDispatch();
  const { user } = useSelector(
        (state) => state.auth
    )

  let { timelinePosts, isLoading } = useSelector((state) => state.post);



  useEffect(()=>{


    //running the api call on first render/refresh 
    dispatch(getTimeLinePosts(user.user._id))

  },[])

  
  

  // const sortedTimelinePosts = arrayForSort.sort(function(a,b){

  //   // console.log(a.updatedAt)
  //   // console.log(b.updatedAt)

  //   return b.createdAt.localeCompare(a.createdAt);  
    

  // })

  //\
  
  


  return (
    <div>
        {timelinePosts ? timelinePosts.map((post, id) => {
            return <Post data={post} key={id} />;
          }):null}
    </div>
  )
}

export default AllPosts

If I use the sortedTimelinePosts (which I commented out) to populate my post it does not work.

When I create the post I get the timeline posts again to rehydrate my state in redux store. Even though the changes reflect in the DevTools, it fails to show in my UI.

// handle post upload
    const handleUpload = async (e) => {
        e.preventDefault();

        // post data
        if(data.description && newPlace.lat && newPlace.long){
            const newPost = {
                userId: user.user._id,
                title: data.title,
                description: data.description,
                latitude: newPlace.lat,
                longitude: newPlace.long,
            };

            console.log(newPost)

            // create post 
            dispatch(createPost(newPost,user))
            
            // rehydrate store
            dispatch(getTimeLinePosts(user.user._id));
            

            setShowModal(false)

            resetShare()



            // Bandage fix
            window.location.reload() 
            


        }

Currently I am refreshing page using 'window.location.reload()' as my UI is not reacting to changes in the store. Can anyone please help?

0 Answers
Related