I am very new with React and I am trying to call the data from server with fetch
api.
If I want to make a helper class to get the data like this one
import { Promise } from 'es6-promise';
import fetch from 'isomorphic-fetch';
let responseData = response => {
return response;
};
let getData = (dataURL, headers) => {
let result = {
data: [],
message: ''
};
if (dataURL === null || dataURL === undefined || dataURL === '') {
result.message = 'URL is not correct';
responseData(result);
}
fetch(dataURL, headers)
.then(response =>{
if (response.ok) {
response.json().then(data => {
result.data = data;
result.message = response.statusText;
responseData(result);
});
}else{
result.message = 'Network response was not ok.';
responseData(result);
}
})
.catch(err => console.log(err));
};
exports.responseData = responseData;
exports.getData = getData;
and whenever the data is available, I will ask the React render the view, during the waiting time, it will show a loading icon.
I put the call inside componentDidMout
but by the time it is executed, the result is always undefined
.
componentDidMount() {
var self = this;
let result = util.getData('http://localhost:3001/menus');
const { dispatch } = this.props;
// dispatch(menuActions.fetchMenusIfNeeded());
if (result !== null && result !== undefined) {
if (this.isMounted()) {
this.setState({
items: result.data.results
});
}
}
}
In Angular, whenever the data is available, it will be updated accordingly but I really don't understand how to do it in React.
EDIT 1: Update the helper class:
import { Promise } from 'es6-promise';
import fetch from 'isomorphic-fetch';
let getData = (dataURL, headers) => {
return fetch(dataURL, headers);
};
exports.getData = getData;
It will always return a Promise
so I can chain handler for data in other components. The only problem that I need to handle the message return by reading Response
object in my components.
In React component:
componentWillMount() {
util.getData('http://localhost:3001/menus')
.then(response =>{
if (response.ok) {
response.json().then(data => {
console.log(data);
this.setState({
items: data.result
});
});
}
})
.catch(err => console.log(err));
}
But whenever it received the data, the render()
function already finished, should I force it to update again?
Fetch data is a basic requirement of practically every React application. There are a variety of ways to fetch data in React, including the built-in Fetch API, Axios, async/await syntax, and others. We'll look at some of these methods in detail. React components can simply fetch their data.
result
is not the data, it is a Promise, which can you use to access the data. You need to return the Promise from fetch and also need to return the data from your then
within getData
, and update your React code.
getData change
return fetch(dataURL, headers)
.then(response =>{
if (response.ok) {
response.json().then(data => {
result.data = data;
result.message = response.statusText;
return responseData(result);
});
} else {
result.message = 'Network response was not ok.';
return responseData(result);
}
})
.catch(err => console.log(err));
React change
componentDidMount() {
var self = this;
let result = util.getData('http://localhost:3001/menus');
const { dispatch } = this.props;
// dispatch(menuActions.fetchMenusIfNeeded());
result.then((data) => {
if (this.isMounted()) {
this.setState({
items: data.results
});
}
});
}
You should not try to delay the rendering and/or mounting of the component until you get a response. Instead you should make use of callbacks to make sure that everything gets updated as you wish once the request is over.
You only need to modify the code for getData
so that it executes a callback once the request is over. You have two options here.
getData
function accept a third parameter callback
and call this method once you handle the response. This would roughly look like the following:let getData = (dataURL, headers, callback) => {
let result = {
data: [],
message: ''
};
if (dataURL === null || dataURL === undefined || dataURL === '') {
result.message = 'URL is not correct';
responseData(result);
}
fetch(dataURL, headers)
.then(response =>{
if (response.ok) {
response.json().then(data => {
result.data = data;
result.message = response.statusText;
responseData(result);
});
}else{
result.message = 'Network response was not ok.';
responseData(result);
}
callback(result);
})
.catch(err => console.log(err));
};
Keep in mind that this is not how an actual implementation would look. In case of an exception the callback wouldn't be invoked and the calling code would never know what happened. But in essence, this is how it would work.
getData
function return the Promise created by the fetch
API. This is the one I'd use personally because it looks cleaner and I'd take Promises over callbacks any day of the week. let getData = (dataURL, headers) => {
let result = {
data: [],
message: ''
};
if (dataURL === null || dataURL === undefined || dataURL === '') {
result.message = 'URL is not correct';
responseData(result);
}
return fetch(dataURL, headers)
.then(response =>{
if (response.ok) {
response.json().then(data => {
result.data = data;
result.message = response.statusText;
responseData(result);
});
}else{
result.message = 'Network response was not ok.';
responseData(result);
}
return result;
})
.catch(err => console.log(err));
};
Just adding the return
keyword would return the Promise and then you would be able to chain handlers to your heart's desire.
OK, how do we make use of this? It's actually pretty straightforward. You now have the ability to tell the getData
method to do something once a Response is received (or an exception raised).
Just as an example, you could do this in your React component's componentWillMount
method.
componentWillMount() {
getData('http://example.com', new Headers())
.then(function(result) {
this.setState({ items: result });
});
}
You can also control the loading panel by setting a flag in the state before the request and resetting it after the request (with callbacks of course).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With