1

So I am working on a React project which has the feature related to that of instagram such that a data is fetched(you can call it feeds).

const feeds = [{
  postId: 1,
  body: "My first post,
  commentList: [{
    commentId: 1,
    comment: "I love this post"
  }],
  isFollowing: true,
  likers: [1]
}, ]

So the visual of each item must have a like/unlike button, follow/unfollow button and create of comment form. I want only the item to be updated instead when i click on the like button on one item it updates other item in the list.

From what i have done so far, when you click the like button, it dispatch an action and update the state to isLike: true which will be used to change the color of the like button but its affecting every item in the list

  1. Function that handle the like and unlike button

       const handleLikeClick = () => {
         const data = {
           postId,
         };
         props.unlikePost(data, token);
       };
       const handleUnlikeClick = () => {
         const data = {
           postId,
         };
         props.likePost(data, token);
       };
    
    1. The view depending on the state depending on the action dispatched

       {isLike ? (
                 <i onClick={handleLikeClick}>
                   <img src={IconLike} alt="" />
                 </i>
               ) : (
      
      )}
    2. The function that handle the request to the api

   export const likePost = (data) => async (
      dispatch
    ) => {
      dispatch(likePostSuccess())
      await axios
        .post(url, data)
        .then((response) => {
          dispatch(likePostSuccess())
        })
        .catch(({ err }) => {
            dispatch(likePostFailure());
        }); 
    }; 
   export const unlikePost = (data) => async (
      dispatch
    ) => {
      dispatch(unlikePostSuccess())
      await axios
        .delete(url,{
          data: {
            postId: data 
          }
        })
        .then((response) => {
          dispatch(unlikePostSuccess())
        })
        .catch(({ err }) => {
            dispatch(unlikePostFailure());
        }); 
    };
  1. The reducer file

const initialState = {
  isLike: false,
}

case Actions.LIKE_POST_SUCCESSFUL:
      return {
        ...state,
        loading: false,
        isLike: true,
      };
      case Actions.LIKE_POST_FAILURE:
      return {
        ...state,
        loading: false,
        isLike: false
      };
      case Actions.UNLIKE_POST_SUCCESSFUL:
      return {
        ...state,
        loading: false,
        isLike: false,
      };
      case Actions.UNLIKE_POST_FAILURE:
      return {
        ...state,
        loading: false,
        isLike: true
      };

So thats what i have so far so once the action is dispatched and the isLike is updated it should change the color of the like button of each item in the list instead of everything in the list. Thanks in advance.

  • I'm not sure I understand the question. if you want to update a value just look through the array in question and update the particular object. – masonCherry Jun 21 '20 at 23:12
  • @MrBrN197 yeah I can look through the array but here I am using react Redux to change the state of the button, so when the action get dispatched it update isLike:true if successful. So that isLike will be used in the component to change the button but when I click on that button to like, it affect other item in the list too – Olatunji Abayomi Jun 21 '20 at 23:23
  • similar issue: https://stackoverflow.com/questions/58015502/react-update-element-of-array-without-rerendering-other-array-elements – Raj Jun 22 '20 at 06:24

2 Answers2

0

The problem is that you have a redux property isLike rather than retrieving the status of the post from the backend. Clearly, a single boolean property cannot represent the state of all the different posts. And what happens if the user refreshes the page? What you need to do is add the property isLiked to the data itself, and have an array of posts in redux which gets updated when someone likes (or unlikes) a post.

However remember that a 'like' is between a user and a post, it is not a property of the post itself. Therefore, the backend would need to be set up in such a way that the data it returns takes into account who it is returning the data to. So the GET request would need to include the user's ID, and the backend would need to pull data from more than one table to create the JSON response.

If you disregard the backend, at the very least you need to add the isLiked field to the post data, keep that array in redux, and update the specific item in the array when the user click like.

see sharper
  • 11,505
  • 8
  • 46
  • 65
0

There is a this pattern where you store all ids in an array and data in an object.

reduxStore: {
 allIds: ['a', 'b', 'c', 'd'], // keys
 byId: {
   a: {isLike: true, loading: false }, 
   b: {isLike: true, loading: false}, 
   c: {isLike: false, loading: true}
}

Now the parent component will subscribe to the allIds (includes keys only) and renders array of child. And each child will subscribe to its own data from component itself. So, updating items in byId object when you need, will affect only itself.

Ref: https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape#organizing-normalized-data-in-state

Raj
  • 116
  • 6