У меня проблема с получением родительского компонента componentWillRecieveProps
для работы с дочерним компонентом.
Если я соберу всю логику в одном компоненте, все будет нормально работать . Тем не менее, я хочу, чтобы элементы публикации были в отдельном компоненте.
Единственный обновляемый объект -
myLikes={post.Likes.length}
Posts.js (Parent)
import React, { Component } from 'react';
import PostList from './PostList';
import {connect} from 'react-redux';
import { withRouter, Redirect} from 'react-router-dom';
import {GetPosts} from '../actions/';
const Styles = {
myPaper:{
margin: '20px 0px',
padding:'20px'
}
,
wrapper:{
padding:'0px 60px'
}
}
class Posts extends Component {
state = {
posts: [],
loading: true,
isEditing: false,
// likes:[]
}
componentWillMount(){
this.props.GetPosts();
// this.setState({
// loading:false
// })
}
componentWillReceiveProps(nextProps, prevState) {
let hasNewLike = true ;
if(prevState.posts !== this.state.posts && this.state.posts>0) {
for(let index=0; index < nextProps.myPosts.length; index++) {
if(nextProps.myPosts[index].Likes.length !==
prevState.posts[index].Likes.length) {
hasNewLike = true;
}
}
}
if(hasNewLike) {
this.setState({posts: nextProps.myPosts, loading:false}) // here we are updating the posts state if redux state has updated value of likes
}
console.log(nextProps.myPosts);
}
render() {
const {loading} = this.state;
const { myPosts} = this.props
console.log(this.state.posts);
if (!this.props.isAuthenticated) {
return (<Redirect to='/signIn' />);
}
if(loading){
return "loading..."
}
return (
<div className="App" style={Styles.wrapper}>
<h1> Posts </h1>
<PostList posts={this.state.posts}/>
</div>
);
}
}
const mapStateToProps = (state) => ({
isAuthenticated: state.user.isAuthenticated,
myPosts: state.post.posts,
})
const mapDispatchToProps = (dispatch, state) => ({
GetPosts: () => dispatch( GetPosts())
});
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(Posts));
PostList.js (ребенок)
import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import {connect} from 'react-redux';
import {DeletePost, postLike, UpdatePost,EditChange, getCount, DisableButton} from '../actions/';
import PostItem from './PostItem';
import _ from 'lodash';
const Styles = {
myPaper: {
margin: '20px 0px',
padding: '20px'
}
}
class PostList extends Component{
constructor(props){
super(props);
this.state ={
title: '',
}
}
// Return a new function. Otherwise the DeletePost action will be dispatch each
// time the Component rerenders.
removePost = (id) => () => {
this.props.DeletePost(id);
}
onChange = (e) => {
e.preventDefault();
this.setState({
title: e.target.value
})
}
formEditing = (id) => ()=> {;
this.props.EditChange(id);
}
render(){
const {posts} = this.props;
console.log(this.props.posts)
// console.log(this.props.ourLikes);
return (
<div>
{posts.map(post => (
<Paper key={post.id} style={Styles.myPaper}>
<PostItem
myLikes={post.Likes.length} // right here
myTitle={this.state.title}
editChange={this.onChange}
editForm={this.formEditing}
isEditing={this.props.isEditingId === post.id}
removePost={this.removePost}
{...post}
/>
</Paper>
))}
</div>
);
}
}
const mapStateToProps = (state) => ({
isEditingId: state.post.isEditingId,
// ourLikes: state.post.likes // reducer likes
})
const mapDispatchToProps = (dispatch) => ({
// pass creds which can be called anything, but i just call it credentials but it should be called something more
// specific.
EditChange: (id) => dispatch(EditChange(id)),
UpdatePost: (creds) => dispatch(UpdatePost(creds)),
postLike: (id) => dispatch( postLike(id)),
// Pass id to the DeletePost functions.
DeletePost: (id) => dispatch(DeletePost(id))
});
export default connect(mapStateToProps, mapDispatchToProps)(PostList);
В качестве альтернативы, если все было в одном компоненте, оно будет работать
Posts.js (все в одном)
import React, {Component} from 'react';
import PostList from './PostList';
import Paper from '@material-ui/core/Paper';
import {connect} from 'react-redux';
import {withRouter, Redirect} from 'react-router-dom';
import {
DeletePost,
postLike,
UpdatePost,
EditChange,
getCount,
DisableButton
} from '../actions/';
import PostItem from './PostItem';
import {GetPosts} from '../actions/';
const Styles = {
myPaper: {
margin: '20px 0px',
padding: '20px'
},
wrapper: {
padding: '0px 60px'
}
}
class Posts extends Component {
constructor(props){
super(props);
this.state = {
posts: [],
title: '',
loading: true,
isEditing: false,
}
}
componentWillMount() {
this.props.GetPosts();
}
removePost = (id) => () => {
this.props.DeletePost(id);
}
onChange = (e) => {
e.preventDefault();
this.setState({title: e.target.value})
}
formEditing = (id) => () => {
this.props.EditChange(id);
}
componentWillReceiveProps(nextProps, prevState) {
let hasNewLike = true;
if (prevState.posts && prevState.posts.length) {
for (let index = 0; index < nextProps.myPosts.length; index++) {
if (nextProps.myPosts[index].Likes.length !== prevState.posts[index].Likes.length) {
hasNewLike = true;
}
}
}
if (hasNewLike) {
this.setState({posts: nextProps.myPosts, loading: false}); // here we are updating the posts state if redux state has updated value of likes
}
}
render() {
const {loading} = this.state;
const {myPosts} = this.props
console.log(this.state.posts);
if (!this.props.isAuthenticated) {
return (<Redirect to='/signIn'/>);
}
if (loading) {
return "loading..."
}
return (
<div className="App" style={Styles.wrapper}>
<h1>Posts</h1>
{/* <PostList posts={this.state.posts}/> */}
<div>
{this.state.posts.map(post => (
<Paper key={post.id} style={Styles.myPaper}>
<PostItem myLikes={post.Likes.length} // right here
myTitle={this.state.title} editChange={this.onChange} editForm={this.formEditing} isEditing={this.props.isEditingId === post.id} removePost={this.removePost} {...post}/>
</Paper>
))}
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
isAuthenticated: state.user.isAuthenticated,
myPosts: state.post.posts, isEditingId:
state.post.isEditingId
})
const mapDispatchToProps = (dispatch, state) => ({
GetPosts: () => dispatch(GetPosts()),
// specific.
EditChange: (id) => dispatch(EditChange(id)),
UpdatePost: (creds) => dispatch(UpdatePost(creds)),
postLike: (id) => dispatch(postLike(id)),
// Pass id to the DeletePost functions.
DeletePost: (id) => dispatch(DeletePost(id))
});
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Posts));