Cannot read property of data null in ReactJs when fetching from JSON - reactjs

I am new to react andtrying to fetch JSON data in React JS but getting this error:
TypeError: Cannot read property 'data' of null
My code is :
import React from 'react';
export default class FetchJson extends React.Component {
componentDidMount()
{
fetch('https://api.myjson.com/bins/9i63i')
.then((response) => response.json())
.then((findresponse) =>{
this.setState({ data: findresponse })
//console.log(this.state.data);
//console.log(findresponse.DesignName);
})
}
render() {
return(
<ul>
{this.state.data.map((x,i) => <li key={i}>{x.DesignName}</li>)}
</ul>
);
}
}
You can see the json data here: http://myjson.com/9i63i
I want to retrieve value for key DesignName which is part1 which is not happening.
See the commented lines: both gives me the value. But when i try to access it inside return method inside render. I get error : TypeError: Cannot read property 'data' of null in this line:
{this.state.data.map((x,i) => <li key={i}>{x.DesignName}</li>)}
How to solve this?

DesignName is not an array in the response.
You can define your state like this:
state = {
data: null
}
And display the DesignName using inline if with logical && operator to solve null problem.
render() {
return (
<div>
DesignName: { this.state.data && this.state.data.DesignName}
</div>
);
}
Codesandbox

You can use an isLoading flag while waiting for your api call to finish.
state = {
data: null,
isLoading:true
}
render() {
if(this.state.isLoading) {
return(<div>loading</div>);
}
return(
<ul>
{this.state.data.map((x,i) => <li key={i}>{x.DesignName}</li>)}
</ul>
);
when your api call has finished, you can update the state like this:
this.setState({ data: findresponse, isLoading:false })

Related

React SetState returns [Object Object] even though api returns valid json

Fetch is successful in below code (I have confirmed by looking at console - Network in browser) but the setState is not updating the allWeights array in state with the array of documents from MongoDB returned by API. When I use console.log() it prints what api returns but just setState is not working. I understand when render() executes allWeights array will have no value however after componentDidMount executes allWeights must have value if setState behaves as expected. I have searched for solutions provided for similar issue but they are not helpful for my issue. As the setState is not working the map function in render() throws error. Kindly help. I am stuck with this for last 3 days.
import React, {Component} from "react";
//
class TeamWeightsMain extends Component {
constructor(props) {
super(props);
this.state = {
allWeights: []
}
}
//
componentDidMount() {
console.log(`Entered componentDidMount()`);
fetch("http://localhost:8080/getallemployees")
.then(response => response.json())
.then((data) => {
this.setState(
{allWeights : data}
);
});
}
//
render() {
console.log(`Entered render() - allWeights value now : ${this.state.allWeights.toString() }`);
if(this.state.allWeights !== undefined && this.state.allWeights.length > 0) {
console.log(`this.state.allWeights.length: ${this.state.allWeights.length}`);
console.log(`this.state.allWeights: ${this.state.allWeights}`);
console.log(`this.state: ${this.state}`);
return(
<main>{
this.state.allWeights.map((emp,i) => {
return <div key={i}>
{emp.empName}
{emp.employeeWeights.map((weight,j) => {
return <div key={j} className="indentWeight">
Date: {new Date(weight.weighedOn).toLocaleDateString()}
{' '}
Weight: {weight.empWeight}
</div>
})}
</div>}
)
}
</main>)
}
else {
console.log(`Inside Not authorized : ${this.state.allWeights}`);
return (
<main>
<h2>Teamweights</h2>
<div className="indentWeights">
Sample text
</div>
</main>
)
}
}
}
//
export default TeamWeightsMain;

Accessing an array that has an object as a value

I'm using the pokeapi to with react. I want to display the values in the types property but can't seem to do so. I get a cannot read property of value 0 undefined. I've tried several methods such as storing the types object in a variable then looping through the elements but I get the same error.
My code is below:
App.js
state = {
pokemonData: []
}
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/mewtwo`)
.then(response => response.json())
.then(data => {
//console.log(data);
this.setState({pokemonData: data});
})
.catch(error => console.log(`Error fetching and parsing data ${error}`));
}
render() {
return (
<>
<Display data={this.state.pokemonData}/>
</>
);
}
Display.js
import React from 'react';
const Display = (props) => {
return (
<>
<h1 className="pokemon-name">{props.data.name}</h1>
<p>{props.data.id}</p>
<p>{props.data.types[0].type.name}</p>
</>
);
}
export default Display;
First of all you initialize your state with an empty array but the data returned by your API is actually an object. Secondly you're trying to render some data by giving an empty array as props (the actual data will come later). So props.data.types doesn't exist and props.data.types[0] will return an error.
Initialize with an empty object
state = {
pokemonData: {}
}
Then in your render function, make sure you have something in your pokemonData before rendering:
return (
<>
{this.state.pokemonData.name !== undefined &&
<Display data={this.state.pokemonData}/>
}
</>
);

Having trouble fetching from an api not sure what I am doing wrong?

I am trying to fetch from an api to and display the data im getting. I have tried using regular fetch with promises and axios and it doesnt seem to be doing anything. Im using the .map() method and I am getting the error map is not a function.
I have tried using fetch and axios to try and get the data from the api.
import React, { Component } from 'react';
class RecentNews extends Component {
state = {
recentArticles: [],
recentReports: [],
isLoaded: false,
}
componentDidMount(){
fetch(`https://spaceflightnewsapi.net/api/v1/articles?page=1`)
.then(response => response.json())
.then(json => this.setState(
{ recentArticles: json,
isLoaded: true,
}
))
}
render(){
let { recentArticles, isLoaded } = this.state
if (!isLoaded) {
return <h1>Loading.....</h1>
}
else {
return(
<div className="recentnews">
<div>
{ recentArticles.map(articles =>
<p>{articles.title}</p>
)
}
</div>
</div>
)
}
}
}
export default RecentNews
here is the error I'm getting
TypeError: recentArticles.map is not a function
▶ 17 stack frames were collapsed.
.map() is a function of Arrays in JavaScript - that API is returning an Object.
It would appear that what you want is the docs array inside that object, so try changing that line to:
{ recentArticles.docs.map(articles =>
The other keys in the object that is returned by that API relate to the pagination. You should use those to create pagination controls, for example, next page, previous page links etc.

Accessing nested json in React

I can successfully fetch json object from the api. However there seems to be a problem in updating the state.
After printing the object I get expected and desired result console.log(videos2.list[0]); gives 1st item from the list attribute of json object, you can check how the api looks under this link:
https://api.dailymotion.com/videos?fields=description,id,thumbnail_url,title,&limit=5&search=cars
However when updating state with setState property selectedVideo: videos.list[0] is undefined.
The code for the component:
class App extends Component {
constructor(props) {
super(props)
this.state = {
videos2:[],
selectedVideo:null
}
this.DMSearch()
}
DMSearch(){
fetch(`https://api.dailymotion.com/videos?fields=description,id,thumbnail_url,title,&limit=5&search=cars`)
.then(result => result.json())
.then(videos2 => {
console.log(videos2.list[0]);
this.setState({
videos2: videos2.list,
selectedVideo: videos2.list[0]
});
console.log(selectedVideo);
});
}
render () {
const DMSearch = this.DMSearch()
return (
<div>
<SearchBar onSearchTermChange= {DMSearch}/>
<VideoDetail video={this.state.selectedVideo}/>
<VideoList
onVideoSelect={selectedVideo=>this.setState({selectedVideo})}
videos2={this.state.videos2}/>
</div>
)
}
}
And exact error is Uncaught (in promise) ReferenceError: selectedVideo is not defined
videos2:list[0] produces correct results, but when assigned to selectedVideo it is undefined
As requested I am also including the code for vide_list which uses the objects form parent component which might be producing error here:
const VideoList = (props) => {
const videoItems = props.videos.map((video)=>{
return (
<VideoListItem
onVideoSelect={props.onVideoSelect}
key={video.etag}
video={video} />
)
})
return (
<ul className="col-md-4 list-group">
{videoItems}
</ul>
)
}
To be specific, this line
const videoItems = props.videos.map((video)=> {
causes the error when reading props. I believe this has something to do with selectedVideo being null...
There is an issue at this line
console.log(selectedVideo);
You printed out an undefined variable. It should be this.state.selectedVideo.
The error selectedVideo is not defined happens because selectedVideo is not a variable, it is a key on the javascript object passed to this.setState function.
//...
this.setState({
videos2: videos2.list,
selectedVideo: videos2.list[0]
});
//...
You can mitigate the error by creating a variable:
DMSearch(){
fetch(`https://api.dailymotion.com/videos?fields=description,id,thumbnail_url,title,&limit=5&search=cars`)
.then(result => result.json())
.then(videos2 => {
console.log(videos2.list[0]);
const selectedVideo = videos2.list[0]; // create variable
this.setState({
videos2: videos2.list,
selectedVideo: selectedVideo
});
console.log(selectedVideo);
});
}

React.js, pulling data from api and then looping through to display

Im new to react. I am trying to pull data from an API, and then loop through it and display it.
Error : Cannot read property 'map' of undefined.
The API data is coming through, but it seems as if React is calling the looplistings before the data is stored into State.
constructor () {
super()
this.state = {
data:'',
}
}
componentWillMount(){
// Im using axios here to get the info, confirmed data coming in.
//Updating 'data' state to equal the response data from the api call.
}
loopListings = () => {
return this.state.data.hits.map((item, i) => {
return(<div className="item-container" key={i}>
<div className="item-image"></div>
<div className="item-details">tssss</div>
</div>)
})
}
loopListings = () => {
return this.state.data.hits.map((item, i) => {
return(
<div className="item-container" key={i}>
<div className="item-image"></div>
<div className="item-details">tssss</div>
</div>)
})
}
render () {
return (
<div>
{this.loopListings()}
</div>
)
}
The reason you are receiving this error is that your call to the API is happening asynchronously to the react lifecycle methods. By the time the API response returned and persisted into the state the render method has been called for the first time and failed due to the fact you were trying to access an attribute on a yet undefined object.
In order to solve this, you need to make sure that until the API response has been persisted into the state the render method will not try to access that part of the state in your render method or to make sure that if it does there is a valid default state in the constructor:
Solve this by changing your render to do something like this:
render () {
return (
<div>
{this.state.data &&
Array.isArray(this.state.data.hits)
&& this.loopListings()}
</div>
)
}
or initialize your constructor like so :
constructor () {
super()
this.state = {
data: {hits: []},
}
}
Remeber react is just javascript and its behavior is just the same.
You could check if desir data.hits exists inside state.
{this.state.data && Array.isArray(this.state.data.hits) ?
this.loopListings()
: null}
Also make sure that, after retrieving a data cal this.setState method like below.
this.setState({ data })

Resources