Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't access nested JSON Objects in React

I have a simple React Component, and am trying to display a nested JSON object in render.

// React Component

class NodeDetail extends React.Component {
  constructor(props) {
    super(props);
    const node = {};

    this.state = {
      node
    }
  }

  componentDidMount() {
    Node.getNode(this.props.node_id).then((result) => {
      console.log(result.data);
      this.setState(() => ({node: result.data}));
    }).catch(function(error) {
      // TODO: handle error
    });
  }

  render() {
    return (
      <div>
        {this.state.node.node_status.name}
      </div>
    );
  }
};

export default NodeDetail;

This is the JSON(stored in result.data) getting returned from a rails API(some fields removed for brevity):

{  
   "id":1234,
   "name":"some-node",
   "created_at":"2018-05-18T15:23:24.012Z",
   "hostname":"some-host",
   "ip":"10.XXX.XXX.XXX",
   "mac":"24:6e:96:XX:11:XX",
   "node_status":{  
      "id":2,
      "name":"Parked"
   }
}

When I access the root level attributes in React with this.state.node.mac , it returns 24:6e:96:XX:11:XX.

When I try to access the name attribute in node_status using this.state.node.node_status.name, I get the the following error:

Uncaught TypeError: Cannot read property 'name' of undefined

I have also tried this.state.node['node_status'].name, and same error.

Why can't I access this object in the JSON, when clearly it is there?

like image 755
grizzthedj Avatar asked Dec 10 '22 06:12

grizzthedj


2 Answers

I bet it's because your call to the Rails API is asynchronous -- so your NodeDetail component tries to render before the API returns data / state is set with the result.data...try putting in a condition for non-existent node_status as some of the other answers have suggested.

So the current (wrong) data flow will be:

  1. constructor. state is set to {node: {}}
  2. componentDidMount. Calls API.
  3. render. Throws exception because this.state.node.node_status is undefined. Component breaks and won't render again...
  4. API returns. state is set to result.data. result.data gets logged to your console.

What you can do is something like:

render() {
    if (!this.state.node.node_status) {
      return null;
    }

    return (
      <div>
        {this.state.node.node_status.name}
      </div>
    );
  }

Or any of the other suggestions to account for the undefined value of this.state.node.node_status.

In general, you need to make sure that your render method will work, even with the default state values set in your constructor.

like image 135
user Avatar answered Dec 12 '22 19:12

user


Error is coming correct Your are fetching data after component loaded In short you are calling your API in componentDidMount You can get rid off from this error in this way

 <div>
        {this.state.node.node_status?this.state.node.node_status.name:""}
 </div>

and I would suggest you to call fetch data API in componentWillMount or constructor which is the initial stage of component.

like image 44
Nishant Dixit Avatar answered Dec 12 '22 18:12

Nishant Dixit