React fetch data and manipulate the response
In this article, we will use react and fetch API to show how to display multi data with one REST API call. To save time we will use React without installing it using npm or yarn.
Starting template will look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fetch data</title></head>
<body>
<div id="react-container"></div>
<!-- Loading React -->
<script src="https://unpkg.com/prop-types/prop-types.js"></script><script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<!-- Our code -->
<script type="text/babel">
const { Component } = React
const { render } = ReactDOM
class App extends Component {
constructor(props) {
super(props)
this.state = {
data: []
}
}
render() {
const {data} = this.state
return (
<div>
<h1>Start point</h1>
</div>
)}
}
render(
<App />,
document.getElementById('react-container')
)
</script>
</body>
</html>
For dummy data we will use https://restcountries.eu/ it’s a great API to learn and try a new idea in React.
First, let’s prepare our constructor and state to receive data:
...
constructor(props) {
super(props)
this.state = {
countryNames: [],
loading:false,
}
}
...
This creates an empty array for data and variable which hold the state of loading.
Next, let’s use React componentWillMount() to fetch data:
...
componentWillMount(){
this.setState({ loading:true })
fetch('https://restcountries.eu/rest/v1/all')
.then(response => response.json())
.then(json => json.map(country => country.name))
.then(countryNames => this.setState({ countryNames, loading: false }))
}
...
In this point, we have assign data from API to our state countryNames.
Next step is to render out data in browser:
...
render(){
const { countryNames, loading } = this.state
return(
<div>
{(loading) ?
<p>Loading Country Names...</p> :
(!countryNames.length) ?
<p>No country Names</p> :
<ul>
{countryNames.map((x,i) => <li key={i}>{x}</li>)}
</ul>}
</div>
)
}
...
This will display our data in the template.
Ready example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fetch data</title></head>
<body>
<div id="react-container"></div>
<!-- Loading React -->
<script src="https://unpkg.com/prop-types/prop-types.js"></script><script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<!-- Our code -->
<script type="text/babel">
const { Component } = React
const { render } = ReactDOM
class App extends Component {
constructor(props) {
super(props)
this.state = {
countryNames: [],
loading: false,
}
}
componentWillMount(){
this.setState({ loading: true })
fetch('https://restcountries.eu/rest/v1/all')
.then(response => response.json())
.then(json => json.map(country => country.name))
.then(countryNames => this.setState({ countryNames, loading: false }))
}
render() {
const { countryNames, loading } = this.state
return (
<div>
{(loading) ?
<p>Loading Country Names...</p> :
(!countryNames.length) ?
<p>No country Names</p> :
<ul>
{countryNames.map((x,i) => <li key={i}>{x}</li>)}
</ul>}
</div>
)}}
render(<App />,document.getElementById('react-container'))
</script>
</body>
</html>
In this scenario, everything goes good and we have response 200 from API and can display data but what if something failed or API doesn't work for the same reason . To protect our code we can apply another promise which will check if everything is ok and will look like this:
...
status(response){
if(response.status >= 200 && response.status < 300){
return Promise.resolve(response)
}else{
return Promise.reject(new Error(response.statusText))
}
}
...
This will change our code because to use this function in a proper way we should bind it to the constructor and create a variable to store error and change template to display the error message.
The code will look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fetch data</title></head>
<body>
<div id="react-container"></div>
<!-- Loading React -->
<script src="https://unpkg.com/prop-types/prop-types.js"></script><script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<!-- Our code -->
<script type="text/babel">
const { Component } = React
const { render } = ReactDOM
class App extends Component {
constructor(props) {
super(props)
this.state = {
countryNames: [],
error:null,
loading: false,
}
this.status = this.status.bind(this)
}
status(response){
if(response.status >= 200 && response.status < 300){
return Promise.resolve(response)
}else{
return Promise.reject(new Error(response.statusText))
}
}
componentWillMount(){
this.setState({ loading: true })
fetch('https://restcountries.eu/rest/v1/all')
.then(status)
.then(response => response.json())
.then(json => json.map(country => country.name))
.then(countryNames => this.setState({ countryNames, loading: false }))
.catch(error => this.setState({ error }))
}
render() {
const { countryNames, loading, error } = this.state
return (
<div>
{(error) ?
<p>Problem with API try againg later.</p> :
(loading) ?
<p>Loading Country Names...</p> :
(!countryNames.length) ?
<p>No country Names</p> :
<ul>
{countryNames.map((x,i) => <li key={i}>{x}</li>)}
</ul>}
</div>
)}}
render(<App />,document.getElementById('react-container'))
</script>
</body>
</html>
Last thing for debuging process how to apply console.log with response in Promise chain:
...
.then(response => response.json())
.then((response) => {
console.log(response,'response');
this.setState({ nations:response });
return response
})
.then(json => json.map(country => country.name))
...
In this example, we use the arrow function to put the response in the object where we can play with it but we must remember to use return state with the response to pass it in the next chain. This code shows a situation where we put all data to nations variable which should be defined in constructor state but this is an example.