Accessing nested json in React - reactjs

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);
});
}

Related

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}/>
}
</>
);

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

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 })

Trouble mapping over data - Cannot read property 'documents' of undefined

I am saving some data (3 documents) into state.
I am receiving 'Uncaught TypeError: Cannot read property 'documents' of undefined' error when trying to map over an array in my react app.
Can anybody see where I am going wrong? 3 items should be mapped in the render function.
export default class Kim extends React.Component<IKimProps, IKimState> {
public constructor(props) {
super(props);
this.state = {
documents: []
}
//SPComponentLoader.loadCss('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
}
componentDidMount() {
axios
.get("https://hiddenforsecurityreasons.com/sites/KIM/_api/lists/getbytitle('MyList')/items?$select=Id,Title,File/ServerRelativeUrl&$expand=File",
{ params:{},
headers: { 'accept': 'application/json;odata=verbose' }
})
.then(response => {
this.setState({
documents: response.data
})
})
.catch(error => {
console.log(error);
});
}
public render(): React.ReactElement<IKimProps> {
return (
<div className={ styles.kim }>
{ setTimeout(function(){
this.state.documents.d.results.map(document => {
<li>{document.Title}</li>
})
}, 6000) }
</div>
);
}
}
Thanks for looking!
When inside the timeout function, this is a reference to that function scope, not your React class scope, so this.state inside the timeout function is actually undefined because there's no state inside the function, so when your code tries to read documents, it can't because you cannot get documents from undefined, as it states.
You can remove your timeout and add an if check around your map call instead.
public render(): React.ReactElement<IKimProps> {
return (
<div className={ styles.kim }>
{this.state.documents.length? this.state.documents.d.results.map(document => <li>{document.Title}</li> ) : null }
</div>
);
}
Another way of dealing with this while keeping your timeout function is to use arrow functions.
While in ES5 ‘this’ referred to the parent of the function, in ES6,
arrow functions use lexical scoping — ‘this’ refers to it’s current
surrounding scope and no further. read more here
try arrow function, for sure it is a problem with this
{ setTimeout(() => {
this.state.documents.d.results.map(document => {
<li>{document.Title}</li>
})
}, 6000) }

API Call Returns Data But Not Render

My console.log shows axios call returns data [object object] but it shows undefined when I try to render the data. Any ideas?
```
class CourseDetail extends Component {
state={
ID: this.props.match.params.ID,
course:[]};
componentDidMount(){
this.runSearch();
}
runSearch=async()=>{
const response= await axios.get('API\?{this.props.match.params.ID}')
this.setState({course: response.data});
//console.log shows course=[object object]
console.log("course="+response.data);
}
render(){
//course is undefined below
const course= this.state.course.map(item=> <div>(item.SUBJECT)</div>)
return (
<div>
{course}
</div>
); }
};
export default CourseDetail;
As #HolyMoly mentioned in the comments, you may need to stringify the response as JSON as well before logging it depending on what the API is returning. There's also a syntax error in your map function, you are using parentheses instead of curly braces to render the value. Depending on the structure of your data response, something like this may work:
class CourseDetail extends Component {
state={
ID: this.props.match.params.ID,
course:[]};
componentDidMount() {
axios.get('API\?{this.props.match.params.ID}')
.then(res => res.json())
.then(res => {
console.log("course="+res.data);
this.setState({course: res.data})
})
}
render(){
//course is undefined below
const course= this.state.course.map(item=> <div>{item.SUBJECT}</div>)
return (
<div>
{course}
</div>
); }
};
export default CourseDetail;
This depends on whether or not the data you are mapping is an object or an array of course. If it is in fact an object, you can map over the keys instead:
const course= Object.keys(this.state.course).map(item=> <div>{item.SUBJECT}</div>)

props value come as undefined but print on browser console

I have this strange issue, not sure what I am doing wrong. I pass a flags object to this components and it is available when I log it on console but it doesn't enter the loop observe logging Object.keys(flags) is undefined. Even when trying to access the value of an object directly, it is undefined.
class Home extends React.Component {
render() {
const allflags = [];
console.log('in Home component flags.. ', this.props.flags);
const {flags} = this.props;
console.log('Object.keys ', Object.keys(flags));
Object.keys(flags).forEach(key => {
console.log('key => ', key);
console.log('value => ', ''+ flags[key]);
allflags.push(<div>{key} : {''+ flags[key]}</div>);
});
console.log('Home Props flags', flags);
console.log('displayWallet >>>>>>>>> ', ''+flags['displayWallet']);
return (
<div>
<h1> All flags</h1>
{allflags}
</div>
);
}
}
Actual Result:
App.js:8 in Home component flags.. {}displayLogonStatus:true displayWallet: true __proto__: Object
App.js:10 Object.keys []length: 0__proto__: Array(0)
App.js:16 Home Props flags {}displayLogonStatus: false displayWallet: true __proto__: Object
App.js:17 displayWallet >>>>>>>>> undefined
Expected Result:
App.js:10 Object.keys []length: 0__proto__: Array(0) - Shouldn't be empty
App.js:17 displayWallet >>>>>>>>> undefined - Should be undefined when it is printed just above.
I think the problem you are having is how you are passing the props to the component.
I can suggest you to debug
console.log(this.props);
and check what is going on inside.
Also, I paste a working example of your code.
class Home extends React.Component {
render() {
const { flags } = this.props;
const allflags = [];
Object.keys(flags).forEach(key => {
allflags.push(<div>{key} : {''+ flags[key]}</div>);
});
return (
<div>
<h1>All flags</h1>
{allflags}
</div>
);
}
}
class App extends Component {
render() {
return (
<Home flags={{ displayLogonStatus: true, displayWallet: true }} />
);
}
}
I hope this helps you

Resources