I am working on a React app that renders components from an array of objects stored in a Firestore document. It is essentially a social media app, and I am trying to develop the 'Like' button to update the 'likes' property on the firestore document for each user post. The problem I am encountering is that since the 'LiveFeed' renders all of the posts using .map, I am having trouble telling my function which post I want to update.
I am able to use the firestore.update method in my action to update all of the likes property on my "posts" collection, but I am not able to isolate a single one that a user would click 'like' on.
Here is the POST component which renders all of the posts from the post collection in firestore using a map method in the parent component
import React from 'react';
import styles from '../../scss/styles.scss';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {newLike} from '../../actions/postActions';
import moment from 'moment';
function Post(props){
const { post, newLike } = props;
console.log(post) //return
function handleNewLike(post){
const currentpost = post;
newLike(post);
}
return(
<div className="container section post">
<div className="card post-card">
<span className="card-title"><h5>{post.authorFirstName} {post.authorLastName}</h5></span>
<div className="card-content center">
<p className="black-text">{post.content}</p>
</div>
<div className="card-action">
<button className="waves-effect waves-light btn" onClick={handleNewLike}>LIKE</button>
<p>likes: {post.likes}</p>
</div>
<div>
<p className="grey-text center">{moment(post.createdAt.toDate()).calendar()}</p>
</div>
</div>
</div>
);
}
const mapDispatchToProps = (dispatch) => {
return{
newLike: (post) => dispatch(newLike(post))
}
}
export default connect(null, mapDispatchToProps)(Post);
Here is the action where I want to update a unique Post likes property (the first function is what creates a post
import * as types from './../constants/ActionTypes';
export const createPost = (post) => {
return (dispatch, getState, {getFirebase, getFirestore}) => {
console.log(post)
const firestore = getFirestore();
const profile = getState().firebase.profile;
const authorId = getState().firebase.auth;
firestore.collection('posts').add({
...post,
authorFirstName: profile.firstName,
authorLastName: profile.lastName,
authorId: authorId,
createdAt: new Date()
}).then(()=> {
dispatch({type: types.CREATE_POST, post});
}).catch((err) => {
dispatch({ type: types.CREATE_POST_ERROR, err});
});
};
};
export const newLike = (post) => {
return (dispatch, getState, {getFirebase, getFirestore}) => {
console.log(post)
const firestore = getFirestore();
firestore.collection('posts').doc(post.id).update({
likes: +1
}).then(()=> {
dispatch({type: types.NEW_LIKE, post});
}).catch((err) => {
dispatch({ type: types.NEW_LIKE_ERROR, err});
});
};
};
Here is the component that maps the array of Posts to the DOM
import React from 'react';
import Post from './Post';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
function LiveFeed(props){
const { posts } = props;
return(
<div className="liveFeed">
<div>
{posts && posts.map(post => {
return (
<Link to={'/post/' + post.id} key ={ post.id }>
<Post post={post}/>
</Link>
)
})}
</div>
</div>
);
}
export default LiveFeed;
You could use React.memo
for your Post
component. And this will tell React to update component only if props have been changed:
const Post = React.memo(function Post(props) {
/* only rerenders if props change */
});
我忽略了一个简单的错误,并没有通过函数传递正确的参数
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.