Reputation: 1429
I'm trying to pass data from my JSON file to my ReactJS app, but receiving the following error:
TypeError: Cannot read property
'mainPage'
of undefined
If I try to console.log siteData
only, it will work well. I am guessing the problem is probably to do with accessing the object parameters
Can you tell me what I'm doing wrong?
Here is my JSON object:
{
"data": {
"mainPage": {
"navBar": ["HR", "HR1", "HR2"],
"name": "Name one",
"agency": "agency one"
},
"secondPage": {
"rank": 2,
"name": "Name Two",
"agency": "agency two"
},
"thirdPage": {
"rank": 3,
"name": "Name Three",
"agency": "agency three"
}
}
}
My .jsx file:
import React from 'react';
import axios from 'axios';
import logo from '../img/company_logo.png';
import '../css/header.scss';
export default class Header extends React.Component {
constructor() {
super();
this.state = {
siteData: {},
};
}
componentDidMount() {
axios.get('./data.json')
.then((res) => {
this.setState({
siteData: res.data,
});
})
.catch((err) => {
console.log(err);
});
}
render() {
// console.log(this.state);
const { siteData } = this.state;
console.log(siteData.data.mainPage);
return (
<div className="headerWrapper">
<a href=".../public/index.html">
<img src={logo} alt="company_logo" id="companyLogo" />
</a>
<ul>
<li>Navbar_1</li>
<li>Navbar_2</li>
<li>Navbar_3</li>
</ul>
</div>
);
}
}
Upvotes: 3
Views: 652
Reputation: 930
Can you please try like this? I have listed data statically and stored in state through setState rather than api call. In render, check if there's data in siteData then only map the data and you can also check by length of siteData.
import React from 'react';
import axios from 'axios';
import logo from '../img/company_logo.png';
import '../css/header.scss';
export default class Roles extends React.Component {
constructor() {
super();
this.state = {
siteData: {},
};
}
componentDidMount = () => {
let allData = {
"data": {
"mainPage": {
"navBar": ["HR", "HR1", "HR2"],
"name": "Name one",
"agency": "agency one"
},
"secondPage": {
"rank": 2,
"name": "Name Two",
"agency": "agency two"
},
"thirdPage": {
"rank": 3,
"name": "Name Three",
"agency": "agency three"
}
}
}
this.setState({ siteData: allData.data })
}
render() {
// console.log(this.state);
const { siteData } = this.state;
console.log(siteData && siteData.mainPage);
return (
<div className="headerWrapper">
<a href=".../public/index.html"><img src={logo} alt="company_logo" id="companyLogo" /></a>
<ul>
<li>Navbar_1</li>
<li>Navbar_2</li>
<li>Navbar_3</li>
</ul>
</div>
);
}
}
Upvotes: 0
Reputation: 30400
The render()
method of your Header component is attempting to access the mainPage
field of data
, which is not initially defined.
Something to keep in mind is that the components render()
method will be called before the axios.get()
request has completed. This typically means you'll want to render a "loading" message, or skip rendering all together (as shown below), while the axio
request is underway.
To apply these ideas, consider revising your component as shown below:
export default class Header extends React.Component {
constructor() {
super();
this.state = {
/* siteData: {}, Remove this */
};
}
componentDidMount() {
axios.get('./data.json')
.then((res) => {
this.setState({
siteData: res.data,
});
})
.catch((err) => {
console.log(err);
});
}
render() {
// console.log(this.state);
const { siteData } = this.state;
/* If siteData not present, then data.json has not been loaded yet, so render nothing */
if(!siteData) {
return null;
}
/* The siteData is present in the component's state, so we can now access it, and render
as per usual */
console.log(siteData.data.mainPage);
return (
<div className="headerWrapper">
<a href=".../public/index.html">
<img src={logo} alt="company_logo" id="companyLogo" /></a>
<ul>
<li>Navbar_1</li>
<li>Navbar_2</li>
<li>Navbar_3</li>
</ul>
</div>
);
}
}
Upvotes: 1
Reputation: 1397
This happens because componentDidMount
runs after the initial render of the component. You can check the lifecycle of a component here where it states:
The componentDidMount() method runs after the component output has been rendered to the DOM.
In the render method you should check if this is null, as with an asynchronous (AJAX) web call, there will be no guarantee you can retrieve the data before the initial render happens, even if you call the AJAX before the render happens.
Upvotes: 1