lifecycle methods are not working as expected

Viewed 203

I want to check if the user is followed by the current user or not. I am running this function in 'componentDidMount'. But I am getting the below error:

UserProfile.js:29 Uncaught (in promise) TypeError: Cannot read property 'includes' of undefined

According to docs, componentdidmount triggers after 1st render. here I should get the value in 1st render through componentWillMount. But it is not happening.

import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import axios from 'axios';
import PostListItem from './PostListItem';
import {getUser, addFollower, addFollowing, removeFollower, removeFollowing} 
from '../actions/user';
class UserProfile extends React.Component{
constructor(props){
    super(props);
     this.state = {
        user:'',
        isFollowed: false
    } 
}

componentWillMount(){
    console.log(this.props.match.params._id);
    axios

.get(`http://localhost:5000/api/user/${this.props.match.params._id}`)
        .then(res => {
            console.log(res.data);
            this.setState({user: res.data});
            this.props.dispatch(getUser(res.data));
        }); 
}

componentDidUpdate(){
    if(this.state.user.following.includes(this.props.currentUser.uid)){
        this.setState({isFollowed: true});
    }
}


render(){
    return(
        <div>
            <div>
                <div className="User-description">
                  {this.state.user.avatar}
                  <img src={this.state.user.avatar} alt= 
{this.state.user.name}/>
                </div>
                {(this.props.currentUser.uid === this.state.user._id) ?
                    <Link to={`/${this.state.user._id}/edit`}>Edit 
Profile</Link> :
                    <button 
                    onClick={this.onFollow}>
                    {this.state.isFollowed? 'Following': 'Follow'}
                </button>
                }
            </div>
)
}

const mapStateToProps = (state) =>{
console.log(state);
 return{ 
     currentUser: state.auth
    // user: state.user.find(user => user._id === props.match.params._id)
 }
};  

export default connect(mapStateToProps)(UserProfile);
2 Answers

Remember, below is an async computation in your code:

axios.get(`http://localhost:5000/api/user/${this.props.match.params._id}`)
        .then(res => {
            console.log(res.data);
            this.setState({user: res.data});
            this.props.dispatch(getUser(res.data));
        }); 

Your promise handler will set the state eventually when rest of the events in the queue are processed. Here componentDidMount() or componentDidUpdate() executes just after the render(). Your then handler wasn't executed until then and thus user.following isn't set in your state. Try putting a check if field following exists then only proceed because eventually it will be set:

componentDidUpdate(){

    if(this.state.user.following && this.state.user.following.includes(this.props.currentUser.uid)){
        this.setState({isFollowed: true});
    }
}

Check user and following before using includes:

if(this.state.user && 
   this.state.user.following.includes(this.props.currentUser.uid)){
Related