Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't access nested object properties in a single object from JSON call in REACT

I'm making an Rails API call and return a single JSON object that has a nested User Object and a tag list array. However, I can't access the nested Object.

this.props.post.user.name throws: Cannot read property 'name' of undefined.

I am confused because when I make the call to PostsIndex in PostsIndex.js and get an array of objects and map through it I can access everything.

Is there something I need to do when only dealing with a single object?

PostShow.js

import React, {Component} from 'react';
import axios from 'axios';
import {Link} from 'react-router-dom';



export default class PostShow extends Component {

constructor(props) {
  super(props)
  this.state = {
    post: {}
  };
}

componentDidMount() {
  const { match: { params } } = this.props;
  axios
    .get(`/api/posts/${params.postId}`)
    .then(response => {
      console.log(response);
      this.setState({ post: response.data});
    })
    .catch(error => console.log(error));

}

  render() {
    return (
      <div>
            <Post post={this.state.post}/>
      </div>
    );
  }
}

class Post extends Component {

  constructor(props) {
    super(props)
  }

  render() {

    return (
      <div>
        <div className="centered">
          <small className ="small" >  | Posted by: {this.props.post.user.name}  on   | Tags:  </small>
          <h3>{this.props.post.title}</h3>
          <img className="image " src={this.props.post.image}/>
        </div>
        <div>
          <p className = "songTitle"> {this.props.post.song_title} </p>
          <p className= "postBody"> {this.props.post.body} </p>
          <div className = "link" dangerouslySetInnerHTML={{ __html: this.props.post.link }} />
        </div>
      </div>
    );
  }
} 

Here is what the JSON object looks like from /api/posts/7:

{"id":7, "title":"adgaadg", "body":"adgadgagdgd", "post_type":"Video", "tag_list":["ERL"], "image":"/images/original/missing.png", "song_title":"adgdgdgd", "created_at":"2018-08-11T21:57:00.447Z", "user":{"id":2,"name":"John","bio":"bio","location":"Reno"}}

like image 533
Alex Erling Avatar asked Jan 27 '23 14:01

Alex Erling


2 Answers

That's because this.props.post.user will be undefined before your request has finished, and trying to access name on that will give rise to your error.

You could e.g. set the initial post to null and not render anything until your request is complete.

Example

class PostShow extends Component {
  constructor(props) {
    super(props);
    this.state = {
      post: null
    };
  }

  componentDidMount() {
    const {
      match: { params }
    } = this.props;
    axios
      .get(`/api/posts/${params.postId}`)
      .then(response => {
        console.log(response);
        this.setState({ post: response.data });
      })
      .catch(error => console.log(error));
  }

  render() {
    const { post } = this.state;

    if (post === null) {
      return null;
    }

    return (
      <div>
        <Post post={post} />
      </div>
    );
  }
}
like image 158
Tholle Avatar answered Jan 31 '23 14:01

Tholle


axios.get is an async operation and <Post post={this.state.post}/> renders before this.setState({ post: response.data}); which means when Post component renders this.state.post is empty object. So what you can do is, initialize your post with null in constructor

this.state = {
   post: null
};

and instead of <Post post={this.state.post}/> do {this.state.post && <Post post={this.state.post}/>} it will render post only if its exists and not null.

like image 45
samee Avatar answered Jan 31 '23 12:01

samee