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