skip to Main Content

In my case I am writing a Facebook clone like application, but much simpler. I put each item in FlatList and render them.

To “like” a post, I press the “like” button on the post and the “like” button turns yellow and the likes count increase by 1 ( Also I call addLike API Function after clicking ), I press it again, it turns gray and likes count decrease by one ( Also I Call removeLike API Funtion ).

This is what I have so far: I store all the loaded posts with redux – this.props, each post has a property called “liked”, which is boolean, indicating whether this user has liked this post or not, when user presses “like”, Now I doing when user like the post I call the addLike() action and fetch all the posts to feed again. I want to do this without fetching data again and again

FlatList Component

<FlatList
          style={styles.postList}
          data={this.props.postData}
          extraData={this.props}
          maxToRenderPerBatch={10}
          keyExtractor={item => {
            return item.id;
          }}
          ItemSeparatorComponent={() => {
            return <View style={styles.separator} />;
          }}
          renderItem={post => {
            const item = post.item;
            this.state.userisLiked = item.likedUsers.find(
              user => user.id == this.state.userDetails.id,
            );
            // console.log('Returning Is Liked ', isLiked);
            return (
              <View style={styles.card}>
                <View>
                  {item.postImage ? (
                    <TouchableOpacity
                      onPress={() =>
                        this.showSelectedImageFullView(item.postImage)
                      }>
                      <ImageBackground
                        style={styles.cardImage}
                        source={{
                          uri: Strings.AWSS3_POST_IMAGE + item.postImage,
                        }}>
                        <View style={styles.overlay} />
                      </ImageBackground>
                    </TouchableOpacity>
                  ) : (
                    <View></View>
                  )}
                </View>

                <View style={{flexDirection: 'row'}}>
                  <Image
                    source={
                      item.user.profilePicture
                        ? {
                            uri:
                              Strings.AWSS3_USER_PROFILE_AVATAR +
                              item.user.profilePicture,
                          }
                        : Images.IMAGE_PLACEHOLDER
                    }
                    style={styles.postUserImage}
                  />
                  <View style={{flexDirection: 'column'}}>
                    <Text style={styles.postUserName}>
                      {item.user.firstName} {item.user.lastName}
                    </Text>
                    <TimeAgo
                      style={styles.postedTime}
                      time={item.createdAt}
                      interval={20000}
                    />
                  </View>

                  <TouchableOpacity
                    style={styles.postMoreInfoIcon}
                    onPress={() => this.toggleModal(item)}>
                    <Image
                      source={Images.POST_MORE_INFO}
                      style={styles.postMoreInfoIcon}
                    />
                  </TouchableOpacity>
                </View>
                <TouchableOpacity onPress={() => this.homeMoreInfoScreen(item)}>
                  <View style={{flexDirection: 'column'}}>
                    <Text style={styles.postTitle}>{item.title}</Text>
                    <Text style={styles.postBody} numberOfLines={2}>
                      {item.description}
                    </Text>
                  </View>
                </TouchableOpacity>
                <View style={styles.cardFooter}>
                  <View style={{flexDirection: 'row'}}>
                    <TouchableOpacity
                      onPress={() => {
                        this.handleUserLikes(item);
                      }}>
                      {this.state.userisLiked ? (
                        <Image
                          source={Images.POST_LIKE_CHECKED}
                          style={{
                            width: 20,
                            height: 20,
                            resizeMode: 'contain',
                          }}
                        />
                      ) : (
                        <Image
                          source={Images.POST_LIKE_UNCHECKED}
                          style={{
                            width: 20,
                            height: 20,
                            resizeMode: 'contain',
                          }}
                        />
                      )}
                    </TouchableOpacity>
                    <Text
                      selectable={true}
                      onPress={() => this.toggleLikeModal(item)}
                      style={{
                        fontFamily: AppStyles.primaryFont,
                        fontSize: 15,
                        color: AppStyles.colorWhite,
                        marginLeft: 5,
                      }}>
                      {item.likesCount} Likes
                    </Text>
                  </View>

                  <View style={{flexDirection: 'row', marginLeft: 20}}>
                    <TouchableOpacity
                      onPress={() => this.homeMoreInfoScreen(item)}>
                      <Image
                        source={Images.POST_COMMENT}
                        style={{width: 20, height: 20, resizeMode: 'contain'}}
                      />
                    </TouchableOpacity>
                    <Text
                      selectable={true}
                      onPress={() => this.homeMoreInfoScreen(item)}
                      style={{
                        fontFamily: AppStyles.primaryFont,
                        fontSize: 15,
                        color: AppStyles.colorWhite,
                        marginLeft: 5,
                      }}>
                      {item.commentsCount} Comments
                    </Text>
                  </View>

                  <View
                    style={{
                      flexDirection: 'row',
                      marginLeft: 10,
                      position: 'absolute',
                      right: 100,
                      top: 20,
                    }}>
                  </View>

                  <View
                    style={{
                      flexDirection: 'row',
                      marginLeft: 10,
                      position: 'absolute',
                      right: 10,
                      top: 20,
                    }}>
                    <TouchableOpacity
                      onPress={() => this.homeMoreInfoScreen(item)}>
                      <Text
                        style={{
                          fontFamily: AppStyles.primaryFont,
                          fontSize: 15,
                          color: AppStyles.colorWhite,
                        }}>
                        Comment
                      </Text>
                    </TouchableOpacity>
                  </View>
                </View>
              </View>
            );
          }}
        />

Handle User Like Action

 //Add Likes to selected post click listner
  handleUserLikes = item => {
    //Check user already liked the post
    const isLiked = item.likedUsers.find(
      user => user.id == this.state.userDetails.id,
    );

    if (isLiked) {
      this.props.removeLikeFromPost(item.id, this.state.user_token);
      this.props.fetchPostData(this.state.user_token);
    } else {
      this.props.addLikeToPost(
        item.id,
        this.state.user_token,
        this.state.userDetails.id,
      );
      this.props.fetchPostData(this.state.user_token);
    }
  };

2

Answers


  1. Chosen as BEST ANSWER

    First of all thanks to @TRomesh for his answer.

    Based on that I found a solution for this issue easily

    My Button Action Call

     handleUserLikes = item => {
        this.props.addLikeToPost({
            item_id:item.id,
            user_token:this.state.user_token,
            user_id:this.state.userDetails.id,
          });
      };
    

    Redux Reducer Function -> This is the part I edited from above answer

    const userLike = (state, payload) => {
      console.log('TCL: userLike -> payload', payload.payload);
      console.log('TCL: userLike -> state.postData', state.postData);
    
      let item = state.postData.find(user => user.id == payload.payload.item_id);
      let local_data = state.postData;
      let isLiked = item.likedUsers.find(
        user => user.id === payload.payload.user_id,
      );
      if (isLiked) {
        local_data = local_data.map(data => {
          if (data.id == payload.payload.item_id) {
            data.likesCount = Number(data.likesCount - 1);
          }
          return data;
        });
      } else if (isLiked == undefined || isLiked == null) {
        local_data = local_data.map(data => {
          if (data.id == payload.payload.item_id) {
            data.likesCount = Number(data.likesCount + 1);
          }
          return data;
        });
      }
      return {...state, postData: local_data};
    };
    

    Cheers !


  2. Assuming that the items are available as props. You can handle the data alteration in the reducer instead of your React component. first what you have to do is

      handleUserLikes = item => {
        this.props.addLikeToPost({
            item_id:item.id,
            user_token:this.state.user_token,
            user_id:this.state.userDetails.id,
          });
      };
    

    inside your redux code fire a function that handles the logic.

    const userLike =(state,payload)=>{
      let Newitem = null;
      let item= state.item.find(
          user => item.id == payload.item_id
        );
      let itemIndex = state.item.findIndex(
          user => user.id == payload.item_id
        );
      let isLiked = item.likedUsers.find(user=>user.id===payload.user_id);
    
       if(isLiked){
         Newitem = {...item,likedUsers:item.likedUsers.filter(user=>user.id!==payload.user_id)}
       } else{
         Newitem = {...item,likedUsers:[...item.likedUsers,payload.user_id]}
       }
      let Newitems = [
        state.items.slice(0, itemIndex),
        Newitem,
        state.items.slice(++itemIndex)
      ];
      return {...state,items:Newitems}
    }
    

    This method userLike should be called inside the reducer switch statement which corresponds to your particular action. like this

    function appReducer(state = initialState, action) {
      switch (action.type) {
       .........
       case 'YOU_ACTION' :
        return  userLike(state,action);
       }
    }
    

    In this manner, you don’t have to fetch the items data again and again. But make sure you send the data to the back end saying the post is liked or unliked.

    const addLikeToPost = (data) => dispatch => {
       // you can send a request to your back end here without Awaiting. 
       // data is passed from the addLikeToPost method called from you react component.
       dispatch({action:'YOU_ACTION',payload:data});
    } 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search