如何更新FlatList中的单个项目-React Native

时间:2020-01-29 04:27:28

标签: react-native redux redux-thunk react-native-flatlist react-props

就我而言,我正在编写类似Facebook的克隆应用程序,但要简单得多。我将每个项目放入FlatList并进行渲染。

要“赞”帖子,请按帖子上的“赞”按钮,然后“赞”按钮变为黄色,并且喜欢计数增加1(也单击,然后调用addLike API函数),再按一次,它会变成灰色,并且点赞次数减少一(我也称为removeLike API Funtion)。

到目前为止,这是我所拥有的:我使用redux存储所有已加载的帖子-this.props,每个帖子都有一个名为“ liked”的属性,该属性为布尔值,指示该用户是否喜欢此帖子,何时用户按下“喜欢”,现在,当用户喜欢该帖子时,我会执行addLike()操作并获取所有帖子以再次供稿。我想做到这一点而不必一次又一次地获取数据

FlatList组件

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

处理用户喜欢的操作

 //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 个答案:

答案 0 :(得分:1)

假设items作为道具可用。您可以在化简器中而不是React组件中处理数据更改。首先,您要做的是

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

在您的redux代码内部触发了一个处理逻辑的函数。

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

应在与您的特定操作相对应的reducer switch语句内部调用此方法userLike。像这样

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

通过这种方式,您不必一次又一次地获取商品数据。但是请确保将数据发送到后端,表明帖子是喜欢还是喜欢。

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

答案 1 :(得分:0)

首先感谢@TRomesh的回答。

基于此,我轻松找到了解决此问题的方法

我的按钮操作呼叫

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

Redux Reducer Function-> 这是我从答案上方编辑的部分

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

干杯!