Why child component cannot get JSON data of parent component with comma(.)? - json

I want to make Main(parent) -> List(child) structure.
Main component gets JSON data with axios and pass inner array of that JSON data to List component (as props). I have done with this, but the problem happens with List component. List component shows the structure and structure[idx] well.
But It cannot reach to inner attributes.
My JSON format is:
"success": true,
"main": {
"xx": 100,
"yy": 0,
"main": [
{
"id": 1,
"state": 1,
"type": "a",
},
{
"id": 2,
"state": 2,
"type": "b",
}, .....
]}
and My code is:
//Main component calls axios
axios1.get(`${URL}`)
.then(res => {
if (res.data.success){
let main = res.data.main['main'];
console.log(test);
this.setState({ main });
}
})
.catch(e => { console.log(e);});
render() {
return ( <List main = {this.state.main}/> );
}
//List component
render() {
const datas = this.props.main;
console.log(datas) //well shown
console.log(datas[0]) // well shown
console.log(datas[0].id) //ERROR: Cannot read property 'id' of undefined
console.log(datas[0].state) //ERROR: Cannot read property 'state' of undefined
return (<div></div>);
}

Related

Data from API is displaying in the console but not in the DOM, why?

I'm learning React and a little about API's. I'm using the Destiny 2 API as a starting API to try to wrap my head around how they work.
Here is my Api.js file:
import React, { Component } from 'react';
import './style.css';
import axios from 'axios';
class Api extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
let config = {
headers: {
'X-API-KEY': 'key-here',
},
};
axios
.get('https://www.bungie.net/Platform/Destiny2/4/Profile/4611686018484544046/?components=100', config)
.then((response) => {
console.log(response);
this.setState({
data: response.data,
});
});
}
render() {
const { item } = this.state;
return (
<div>
{Array.isArray(item) &&
item.map((object) => <p key={object.data}>{object.data.Response.profile.data.userInfo.displayName}</p>)}
</div>
);
}
}
export default Api;
The data from the API is returned as an object that contains a nested array. I can get the data to display in the console no problem.
This is the layout of the response object output to the console:
I'm trying to grab the value of "displayName" and output it into the DOM, what am I doing wrong?
I have tried returning the data as JSON by doing:
response => {return(data.json())} and iterating through the json object using {Object.keys(this.state.data).map((key) => but I have still managed to only get data in the console and not in the DOM.
Is there anything that seems to be missing? I've been stuck with this problem for several days now!
EDIT: This is the whole response from the API call
{
"Response": {
"profile": {
"data": {
"userInfo": {
"membershipType": 4,
"membershipId": "4611686018484544046",
"displayName": "Snizzy"
},
"dateLastPlayed": "2019-04-05T14:28:30Z",
"versionsOwned": 31,
"characterIds": [
"2305843009409505097",
"2305843009411764917",
"2305843009425764024"
]
},
"privacy": 1
}
},
"ErrorCode": 1,
"ThrottleSeconds": 0,
"ErrorStatus": "Success",
"Message": "Ok",
"MessageData": {}
}
In the render function, where you destructure you state, you have the wrong property.
const { item } = this.state; should be const { data } = this.state;
More about destructuring here.
Also, you need to make changes here:
EDIT: Actually, your data isn't even an array. You don't have to iterate through it.
<div>
<p>{data.Response.profile.data.userInfo.displayName}</p>}
</div>
Let's do a check to make sure that we got back the api before running. You might be rendering before the api call is finished. Try using an inline statement.
{ item ? {Array.isArray(item) && item.map(object => (
<p key={object.data}>{object.data.Response.profile.data.userInfo.displayName}</p>
))}
:
<div>Loading...</div>

Can't render an array inside of the ReactJS state

I'm fetching the data from an external API for food recipes, and getting the response in this format (JSON):
{
"count": 30,
"recipes": [
{
"publisher": "BBC Food",
"f2f_url": "http://food2fork.com/view/8c0314",
"title": "Chicken and cashew nut stir-fry",
"source_url": "http://www.bbc.co.uk/food/recipes/chickenandcashewnuts_89299",
"recipe_id": "8c0314",
"image_url": "http://static.food2fork.com/chickenandcashewnuts_89299_16x9986b.jpg",
"social_rank": 95.91061636245128,
"publisher_url": "http://www.bbc.co.uk/food"
},
{
"publisher": "Jamie Oliver",
"f2f_url": "http://food2fork.com/view/0beb06",
"title": "Roasted chicken breast with pancetta, leeks & thyme",
"source_url": "http://www.jamieoliver.com/recipes/chicken-recipes/roasted-chicken-breast-with-pancetta-leeks-and-thyme",
"recipe_id": "0beb06",
"image_url": "http://static.food2fork.com/466_1_1349094314_lrg2129.jpg",
"social_rank": 94.88568903341375,
"publisher_url": "http://www.jamieoliver.com"
},
{ ... more recipes ... }
]
}
And I'm trying to access that data and display, for the purpose of testing, just variables 'count', and the 'publisher' of the first recipe in array. This is my React code:
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { data: {} };
}
componentDidMount() {
fetch('https://www.food2fork.com/api/search?key=MY_KEY&q=chicken%20breast&page=2')
.then(response => {
return response.json();
})
.then(jsonData => {
this.setState({ data: jsonData }, function() {
console.log(jsonData);
});
});
}
render() {
return (
<div className="App">
<h1>{this.state.data.count}</h1>
<p>{this.state.data.recipes[0].publisher}</p> // Why this doesn't work?
</div>
);
}
};
If I remove the 'p' tag in the render() function, everything works as expected: the page loads at first, and then after fetching the data, displays '30' as 'h1'.
However, if I run the code with the 'p' tag, I get this error:
I'm searching for the answers for more than two hours and really can't find the answer. Why can I access the variable 'count', but not the variable 'publisher', which is inside of an array? I'm event logging out this.state after setting it, and object looks completely normal there. How can I access the elements in the 'recipes' array?
This is is because when you are fetching data at that time react render the component and you got error as this.state.data is still {} so this.state.data.recipes[0] is yet not defined as fetch request is not completed (it take some time). To resolve it you have to return on 2 conditions.
when fetch is running (Loading)
2) when fetch is completed
render() {
if(!this.state.data.recipes){
// if the fetch request is still not completed
return (
<div>
<h1>Loading .... </h1>
</div>
)
}
// run when fetch request is completed and this.state.data is now assigned some data
return (
<div className="App">
<h1>{this.state.data.count}</h1>
<p>{this.state.data.recipes[0].publisher}</p> // Why this doesn't work?
</div>
);
}
answer for your comment.
the error is can not read property 0 of undefined which means this.state.data.recipes is undefined and thus.state.data.recipes[0] is error right?.
But when you use this.state.data.count then you did not get error. As it will print undefined that is value of count (at that moment and you are not trying to print further like this.state.data.count.toString() if you do so it will through you error can not read property toString() of undefined).
and in then() when you use this.setState() it will update the state and react will re-render all affected components.

Objects are not valid as a React child : Error while using setState

I am getting the above mentioned error.I have gone through the related thread links but not solving my issue.I understood that this issue come when I am trying to set the state with an object rather than using array.
I have one siteProductTestContainer.js
import React from "react";
import api from "../networking/api";
import ProductList from "./components/ProductList";
class siteProductTestContainer extends React.Component {
state = {
products: []
};
componentDidMount = () => {
//make an api call to get the data
const dataToSend = {
customerNumber: this.props.propsAppData["customerNumber"],
elid: this.props.propsAppData["elid"]
};
const callback = responseData => {
console.log("DataType of products-->", typeof this.state.products); //object
console.log("DataType of responseData", typeof responseData); //object
console.log("DataType of responseData.services-->", typeof responseData.services);
//object
this.setState({
products: responseData.services
});
console.log("After updating state");
console.log("Current state is ", this.state);
api.siteProduct(dataToSend, callback);
};
render() {
return ( <
div >
<
ProductList productList = {
this.state.products
}
name = "pourush" / >
<
/div>
);
}
}
export default siteProductTestContainer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/react.min.js"></script>
So,Suppose I am getting the data in responseData as :
{
"site-services": {
"cNum": "the customer number to whom the service belong to",
"eId": "the site elid whose services are requested",
"services": [
{
"name": "service 1",
"serviceId": "123456"
},
{
"name": "service 2",
"serviceId": "147852"
}
]
}
}
Question : In responseData,I am already getting services as an array of objects,but still I am not being able to map using setstate() ?
services in not directly available under responseData, you need to get it from "site-services" like
this.setState({
products: responseData["site-services"].services
});
Usually,these type of error Occurs where your components are nested and you are trying to pass down the the data from parent component to the child one.
The Error gets bubbled up and shown at the top component, but actually the error occurs at the Inner child.
And Somewhere in Inner child component, we need to loop in Array of objects to extract the data and render it correctly.
I debugged from parent to child and that worked for me.

How to access nested json inside jsx component in react native?

I am trying to list the server response , but some mistake is their in my code about accessing nested json..Following is the structure of json
Updated:
{
"child": [],
"courses": [{
"data": {
"name": "Student 1",
"date_created": 1514610451,
"total_students": 4,
"seats": "",
"start_date": false,
"categories": [{
"name": "Subject",
"slug": "Subject"
}],
"intro": {
"id": "1",
"name": "Main Admin",
"sub": ""
},
"menu_order": 0
},
"headers": [],
"status": 200
}]
}
And my react part is
render(){
return this.state.course.map(course =>
<Text style={styles.userStyle}>{course.courses.data.map(datas => datas.name)}</Text>
);
}
Please help me to figure out the mistake.I am getting this.state.course.map is not a function.My fetch request is as follows
state= {course:[]};
componentWillMount(){
fetch('https://www.mywebsite.com/' + this.props.navigation.state.params.id)
.then((response) => response.json())
.then((responseData) => this.setState({course: responseData}))
}
So you would need to show us how this.state is set, but if you're doing something like this.setState(jsonObject), the property you are looking for seems to be this.state.courses. This would access the array of courses. However, in the subsequent lines you try to access course.courses, which suggests you're setting the state like this.seState({course: jsonObject}) so it's not clear.
I'd say if you fix the first problem, you'll immediately hit another one because it doesn't look like data is an array but an object, so trying to call map on it is unlikely to do what you want (unless you've been playing with prototypes).
EDIT:
In response to the new info, I recommend the following:
render(){
if(this.state.course && this.state.course.courses) {
return this.state.course.courses.map(course =>
<Text style={styles.userStyle}>{course.data.name}</Text>
);
} else {
return [];
}
}

Nested JSON with objects and arrays, find value

Im building a React app and I have a quite complex JSON file where I need to find and output certain values of an object in an array.
Im trying to output all my people from my JSON, they look something like this:
people: [
{
"id": 1,
"email": "Sincere#april.biz",
"address": [
{
"street": "Kulas Light",
"type": "house",
"attribute": {
"sketch": "sketch.jpg",
"photo": "photo.jpg"
}
},
{
"street": "Lorem Ipsum",
"type": "apartment",
"attribute": {
"sketch": "sketch.jpg",
"photo": "photo.jpg"
}
}
]
}
]
I have no problem to output the email, doing it like so:
var App = React.createClass({
getInitialState: function () {
return {
results: {}
}
},
componentDidMount() {
fetch(REQUEST_URL) // fetch from API, returns JSON
.then(res => res.json())
.then(data => {this.setState(
{ results: data.people}
);
})
},
renderResult : function(key){
return <Result key={key} index={key} details={this.state.results[key]}/>
},
render : function() {
return (
<ul>
{Object.keys(this.state.results).map(this.renderResult)}
</ul>
)
}
});
var Result = React.createClass({
render : function() {
return (
<li>
{this.props.details.email}
<img src="{this.props.details.address.type=house.attribute.photo}"/>
</li>
)
}
});
ReactDOM.render(App, document.querySelector('#app'));
However, now I need to output "photo" but only for "type": "house". I tried this but no luck, well aware that this is way off. Im quite new to handling JSON data and React and Google hasn't helped me even after a few hours of trying to solve this.
The .address property isn't an object but an array of objects so
.type is not available directly on .address:
this.state.results.people.address.type
// .type property doesn't exist on array
Solution:
You can use Array.prototype.filter on .address to obtain an array of objects that have a property type whose value is "house":
var houseAddresses = this.state.results.people.address.filter(function(value){
return value.type === "house";
});
Here, houseAddress will be an array of objects whose type value is 'house".
You can then loop through the array to create the relevant JSX using for, Array#forEach or Array#map. The following example uses Array#map:
const houseImgTags = houseAddresses.map(function(house, index){
return (
<img
src={house.attribute.photo}
key={'house'+index}
/>
);
});
(A key was added here in case there are more than one instance of a house object)
You can simply write.
<img src={this.states.results.address.type==="house"?house.attribute.photo : otherwise_photo}/>
Basically this would compare address.type is house or not,then return the result corresponded.

Resources