How to efficiently fetch data from URL and read it with reactjs? - json

I have some URL with json and need to read data.
For the sake of this example json looks like this:
{
"results": [
...
],
"info": {
...
}
}
I want to return fetched data as a property of a component.
What is the best way to do it?
I tried to do that with axios. I managed to fetch data, but after setState in render() method I received an empty object. This is the code:
export default class MainPage extends React.Component {
constructor(props: any) {
super(props);
this.state = {
list: {},
};
}
public componentWillMount() {
axios.get(someURL)
.then( (response) => {
this.setState({list: response.data});
})
.catch( (error) => {
console.log("FAILED", error);
});
}
public render(): JSX.Element {
const {list}: any = this.state;
const data: IScheduler = list;
console.log(data); // empty state object
return (
<div className="main-page-container">
<MyTable data={data}/> // cannot return data
</div>
);
}
}
I don't have a clue why in render() method the data has gone. If I put
console.log(response.data);
in .then section, I get the data with status 200.
So I ask now if there is the other way to do that.
I would be grateful for any help.
----Updated----
In MyTable component I got an error after this:
const flightIndex: number
= data.results.findIndex((f) => f.name === result);
Error is:
Uncaught TypeError: Cannot read property 'findIndex' of undefined
What's wrong here? How to tell react this is not a property?

Before the request is returned, React will try to render your component. Then once the request is completed and the data is returned, react will re-render your component following the setState call.
The problem is that your code does not account for an empty/undefined data object. Just add a check, i.e.
if (data && data.results) {
data.results.findIndex(...);
} else {
// display some loading message
}

In React, after you have stored your ajax result in the state of the component (which you do appear to be doing), you can retrieve that result by calling this.state.list
So to make sure this is working properly, try <MyTable data={this.state.list}>
https://daveceddia.com/ajax-requests-in-react/

Related

Console.log returns json response with two objects of the same key name

I have an object with two nested objects with the same key names (data), the second object has a nested object with same name(data). I'm trying to access the number and letter keys of the nested second object. My goal is to select the second data object and 'ignore' the first one so it doesn't show up in my console.log as undefined. Any help would be greatly appreciated.
index.js get api endpoint and return response.
const worldData = 'https://disease.sh/v3/covid-19/all';
export const fetchWorldData = async () => {
try {
const response = await axios.get(worldData);
return response;
} catch (error) {
console.log(error);
}
};
App.js set data to state object and pass it down to props
import { fetchWorldData } from './api';
class App extends React.Component {
state = {
worldData: {},
};
async componentDidMount() {
const fetchedWorldData = await fetchWorldData();
this.setState({
worldData: fetchedWorldData,
});
}
render() {
const { worldData } = this.state;
return (
<div>
<WorldDisplay data={worldData} />
</div>
);
}
}
export default App;
Component with props
import React from 'react';
const WorldDisplay = (data) => {
console.log(data);
return (
<div>
<h1> hello world</h1>
</div>
);
};
export default WorldDisplay;
This is what appears when console.log
{
{data: _proto_},
// I want to access nested data object below
{data: data:{updated: 1594404341270, cases: 12507540, ...}
}
What you're actully getting are two console logs. The first one is blank or empty, so what it shows on console is it's _proto or portotype (inherited props and methods from its basic form; JS Object in this case)
The second log gets the response with actual data.
It does have only one prop: data. It's structure is
{
config: Object
data: Object
headers: Object
request: XMLHttpRequest
status: Number
statusText: String
}
What you want is the data prop inside this (so it's data.data) which contains this
{
active: Number
activePerOneMillion: Number
affectedCountries: Number
cases: Number
casesPerOneMillion: Number
critical: Number
criticalPerOneMillion: Number
deaths: Number
deathsPerOneMillion: Number
oneCasePerPeople: Number
oneDeathPerPeople: Number
oneTestPerPeople: Number
population: Number
recovered: Number
recoveredPerOneMillion: Number
tests: Number
testsPerOneMillion: Number
todayCases: Number
todayDeaths: Number
todayRecovered: Number
updated: Number
}
To access it within your code, try this:
const WorldDisplay = (data) => {
if(data.data && data.data.data)
console.log(data.data.data);
return (
<div>
<h1> hello world</h1>
</div>
);
};

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>

TypeScript Access Data from a Successfully Received Promise

I am using the React Framework with TypeScript.
My Problem is that I am trying to access Data from a successfully received promise using the fetch-method. So that i can already see (in the browser console) that there is an array with the needed data containend in the promise. That's my browser console output: Chrome Console Output
The fetch is beeing executed as soon as the component mounts and saves the results in the state:
constructor(){
super();
this.processJSON = this.processJSON.bind(this);
this.state = {
buecherJSON : []
}
}
componentDidMount() {
fetch('http://localhost:8080/buecher/findAllByIsbnIsBefore?anzahl=2')
.then(results => {
this.setState({
buecherJSON : results.json()
});
})
.catch((error) => {
console.error(error);
});
}
In separate method I want to process the JSON formatted data to make an object out of it. But I can't figure out how to make that. So i far i got this (which is basically doing nothing):
processJSON(){
var buecherJSON = this.state;
console.log(Object.assign({},buecherJSON));
}
How can I map the received JSON to an accessible array in TypeScript?

ReacJs and fetch json and update state prop

I'm a bit disappointed of my results about getting started with reactjs.
I'm now just trying to parse json data from a simple restful ws.
If I put on chrome the url of rest get query, it answers correctly a json array:
[{"label":"TestLabel!!","value":7,"rating":17.25},{"label":"TestLabel2 !!","value":8,"rating":18.25}]
this is my React component:
export default class ItemLister extends React.Component {
constructor() {
super();
this.state = { items: [{"label":"Test1!!","value":7,"rating":17.25}] };
}
componentDidMount() {
fetch('/rest/json/product/get')
.then(result=> {
this.state.items.push(result);
});
}
render() {
return(
<div>
<div>Items:</div>
{
this.state.items.map(function(item, i){
return <div key={i}>{item.label}</div>
}
)}
</div>
);
}
}
This, after lots of tweaking, shows no errors, but nothing happens to the list, which shows only the constructor element.
Pls point me to the right direction...
thanks
SOLVED:
the "setState()" as suggested was part of the problem.
The other part is the way i manage the json answer.
This way the project works:
componentDidMount() {
fetch('/rest/json/product/get')
.then(response => response.json())
.then(response => {
this.setState({items: response });
})
}
But I just tried another way to implement the call by chance since i was totally lost.
I feel a bit confused. What is the correct way to implement a fetch?
Anyways...this is ok.
Read the last line in the Docs:
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
try this:
this.setState((state) => ({ items: state.items.concat(result) }))
or you can do this if result is array:
this.setState({ items: [...this.state.items , ...result] })
try this.setState('items',result)

Why is my props undefined when i passed a defined state through?

I am trying to pass data to a child component and I keep getting an undefined prop. I think it may have an issue with when Im setting the state in the parent component. Should i not be using componentWillMount?
export default class AllItems extends Component {
constructor () {
super()
this.state=({ user: cookie.load('user')})
this.httpHandler = axios.create({
baseURL: 'http://localhost:3000/',
headers: {
'Authorization': this.state.user.token
}
})
}
componentWillMount() {
this.httpHandler('/products/')
.then(function (response) {
this.setState({ winks: response.data.data})
console.log(this.state.winks)
}.bind(this))
}
render() {
return (
<Winks products={this.state.winks} />
)
}
}
The problem is that your promise may not return before componentWillMount finishes and render is called. So products won't exist yet. You could do something like this:
render() {
if (this.state.winks) {
return (<Winks products={this.state.winks} />)
} else {
return (<div>No Winks yet</div>);
}
}
the problem is that you do not have an initial state for winks Since you are relying on an ajax call to set the state of winks, the ajax call will take place asynchronously and then it will execute the render function before the api call finishes causing this.state.winks to be undefined initially.
You could do something like this
render() {
let content = this.state.winks ? <Winks products={this.state.winks} /> : <div/>
return <div> {content} </div>