I'm trying to make a social media app using react, react-redux and firebase. I want to implement like-unlike feature. I tried creating the like button and it is storing the username in firebase in order to avoid a user liking the same post repeatedly. But, now I'm not sure how to traverse through the LikedBy data stored in firebase to show the like button if the current user hasn't liked the post and unlike button in the opposite case. This is how I'm storing a user who has liked a post in firebase realtime database.
This is my likepost action.
export const likePost = (username, postId) => {
const req = {
username,
postId
}
return (dispatch) => {
axios.post('/Data/' postId '/LikedBy.json', req)
.then((res) => {
dispatch({
type: actionTypes.Like_Post,
payload: res
})
})
}
}
This is the reducer.
case actionTypes.Like_Post:
return {
...state,
Data: state.Data.map((post) => post.id === action.payload.postId
? {...post, LikedBy: post.LikedBy.concat(action.payload.username)}:post)
}
How do I remove a user from likedby field in firebase if they click the unlike button? Is there a better way to do this?
EDIT I tried the below solution by Mateusz Ciesla but it didn't quite work for me. This is how I'm rendering posts to the screen. I used a tertiary operator to display the unlike button if the user has already liked that post. I haven't set up the unlike function yet but can be differentiated by their styles. But this isn't working I only see the like button, the button does not change to the unlike button even after the like has been stored in firebase.
{this.props.data.reverse().map((res) => {
let newString = res.LikedBy.username '';
let list = newString.split(" ");
let boolButton = false;
if(list.indexOf(this.props.user) !== -1){
boolButton = true;
}
return(
<div>
<Card
key={res.id}
className="Cards"
>
<Card.Body
className="container">
<h6>
@{res.User}
</h6>
<Card.Text>
{res.Comment}
</Card.Text>
<div>
<center>
<img className="cardImgStyle" alt="bin" src={res.ImageUrl} />
</center>
</div>
<div className="bottomButtons">
{ boolButton ? <Button className="btn btn-primary likeDislike"
id="likeButton"
>
<FontAwesomeIcon icon={faThumbsUp} style={{width:"15px", color:"white"}}/>
</Button> : <Button className="btn btn-light likeDislike"
id="likeButton"
onClick={() => this.props.onLikePost(this.props.user, res.id)}
>
<FontAwesomeIcon icon={faThumbsUp} style={{width:"15px"}}/>
</Button>
}
</Card>
</div>
CodePudding user response:
To remove a like you need to retrieve the string containing all the usernames, split it into a list containing the individual usernames, find the index of the username you want to remove, splice it from the list, convert the list to string and set the resulting string as the new likedBy
parameter.
let newString = doc.data().likedBy;
let newList = newString.split(" "); //convert string to list containing individual usernames
let index = newList.indexOf("UsernameToBeRemoved"); //find index of username to remove
newList.splice(index, 1); //remove string from list
newString = newList.join(" "); //convert list back into string where each username is separated by space
//then set the new string as the field in your firebase document
This will remove the username from the liked list, just make sure to not have duplicate usernames in it.
Then to check if the current user liked the post:
if (newList.indexOf(username) != -1)
//display like
CodePudding user response:
EDIT REPLY: React will only rerender a component after state, eg. from the useState hook, changes. For your button to change you need to store a duplicate object of the firebase document in your component state.
The best solution would be to update the object stored in the component state and set it to the firebase document every time it changes.
Just make sure to set a new object to the state every time, using for example setState(Object.assign({}, oldState));
, otherwise it won't rerender either.