Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 25, 2023 08:12 pm

Fetching Data in Your React Application


React is arguably the most popular library for building interactive web applications. However, React is not a full-fledged web framework. It focuses on the view part of the venerable MVC model. 


There is a whole React ecosystem that addresses other aspects. In this tutorial, you'll learn about one of the most basic elements of any web application—how to fetch data to display. This is not trivial. There are several places in the React component hierarchy where you can fetch data. When to fetch data is another concern. You also need to consider what technology to use for fetching your data and where to store it. 


At the end of this tutorial, you'll have a clear picture of how data fetching works in React, the pros and cons of different approaches, and how to apply this knowledge to your React applications.


Getting Started


Let's create a skeleton for our React app with create-react-app:





1
create-react-app react-data-fetcher

The result is a pretty elaborate directory structure. Read the excellent README file if you're unfamiliar with create-react-app.


Creating a Simple Server


I created a simple server for storing and serving quotes. It is not the focus of this tutorial, and its role is to provide a remote API for demonstrating how to fetch data with React. Just to satisfy your curiosity, it is a Python 3 application based on the hug framework and uses Redis as persistent storage. 


The API is extremely simple. There is a single endpoint, /quotes. It returns all the stored quotes in response to an HTTP GET request, and you can add new quotes by sending an HTTP POST request.


The full source code is available on GitHub.


Demo App Overview


The demo app is a React application that communicates with the quote service, displays all the quotes, and lets you add new quotes. 


The app structure is very simple. I started with a skeleton created by create-react-app and added two components in the src sub-directory: QuoteList and AddQuoteForm. Here is the directory structure (excluding node_modules):


 






















































































1
~/git/react-data-fetcher > tree -I node_modules -L 2
2
.
3
├── README.md
4
├── README2.md
5
├── package.json
6
├── public
7
│   ├── favicon.ico
8
│   ├── index.html
9
│   └── manifest.json
10
├── src
11
│   ├── AddQuoteForm.css
12
│   ├── AddQuoteForm.js
13
│   ├── App.css
14
│   ├── App.js
15
│   ├── App.test.js
16
│   ├── QuoteList.js
17
│   ├── index.css
18
│   ├── index.js
19
│   └── registerServiceWorker.js
20
└── yarn.lock
21
2 directories, 16 files

The full source code is available on GitLab.


Displaying Quotes


The QuoteList functional component displays a list of quotes as a bullet list. It expects an array of strings:



















1
import React from 'react'
2
const QuoteList = ({quotes}) =>
3
  quotes.map(quote => <li key={quote}>{quote}</li>) 

4
export default QuoteList

It is a child component of the main App component.


Fetching Data With the Fetch API


The Fetch API is a promise-based API that returns a response object. In order to get to the actual JSON content, you need to invoke the json() method of the response object.







































1
 fetchQuotes = () => {
2
    this.setState({...this.state, isFetching: true})
3
    fetch(QUOTE_SERVICE_URL)
4
      .then(response => response.json())
5
      .then(result => this.setState({quotes: result, 
6
                                     isFetching: false}))
7
      .catch(e => console.log(e));
8
  }
9
}

Placing Your Data-Fetching Code


React is, of course, all about components. The question of where to place data-fetching code is important. If you factor your code well, you'll have a lot of generic components and some application-specific components. React and JavaScript in general are very flexible, so it is possible to inject logic anywhere. 


Fetching quotes from a REST API requires some form of polling, since I want the quotes to be always up to date. But the initial fetch is also important. React components have lifecycle methods where you can implement logic that will execute at a particular time. The componentDidMount() method fires when the component can be accessed and its state modified. It is the perfect spot to initiate data fetching. 


Here is what it looks like:















1
componentDidMount() {
2
    this.fetchQuotes()
3
  }

If you really want to cut down on the time to first view, you may consider using the componentWillMount() to initiate your async fetching, but you risk having the fetch complete before the component is mounted. I don't recommend this approach.


Check out Mastering the React Lifecycle Methods for further details.


Choosing How Often to Fetch Data


The initial fetch in componentDidMount() is great, but I want to update the quotes frequently. In a REST-based API, the only solution is to periodically poll the server. The quote service is very basic and always returns all the quotes. 


More scalable services will provide a way to check for updates or even using HTTP if-modify-since or eTag. Our demo application just fetches everything every five seconds by starting a timer in componentDidMount() and cleaning up in componentWillUnmount():



































1
componentDidMount() {
2
    this.fetchQuotes()
3
    this.timer = setInterval(() => this.fetchQuotes(), 5000);
4
  }
5
  
6
  componentWillUnmount() {
7
    this.timer = null;
8
  }  

The polling duration is an app-specific decision. If you need real-time updates and/or polling is stressing the back end too much, consider using WebSockets instead of REST.


Dealing With Long-Running Data Fetching


Sometimes data fetching can take a long time. In that case, displaying a progress bar or a shiny animation to let the user know what's going on can contribute a lot to the user experience. This is especially important when the user initiates the data fetching (eg. by clicking a search button). 


In the demo app, I simply display a message saying "Fetching quotes..." while a fetch is ongoing. In the render() method of the main App component, I utilize conditional rendering by checking the state.isFetching member. 



















































1
render() {
2
    const title = 'Quotes for ya!'
3
    let now = new Date()
4
    return (
5
      <div className='App'>
6
        <h2 className='App-title'>{title}</h2> 

7
        <p>{this.state.isFetching ? 'Fetching quotes...' : ''}</p> 

8
        <QuoteList quotes={this.state.quotes} /> 

9
        <AddQuoteForm quote_service_url={QUOTE_SERVICE_URL}/> 

10
      </div> 

11
    );
12
  }

The fetchQuotes() method takes care of updating state.isFetching by initializing it to true when it starts and setting it back to false when receiving the quotes:







































1
 fetchQuotes = () => {
2
    this.setState({...this.state, isFetching: true})
3
    fetch(QUOTE_SERVICE_URL)
4
      .then(response => response.json())
5
      .then(result => this.setState({quotes: result, 
6
                                     isFetching: false}))
7
      .catch(e => console.log(e));
8
  }
9
}

Handling Errors


I do the very minimum of error handling here by logging caught errors to the console. Depending on your application, you may invoke some retry logic, notify the user, or display some fallback content.


Using Axios


An alternative to the Fetch API is Axios. Many developers choose to replace Fetch with Axios because of the extra power and convenience of the Axios library.


Here is what the fetchQuotes function would look like with Axios:































1
 fetchQuotes = () => {
2
    this.setState({...this.state, isFetching: true})
3
    axios.get(QUOTE_SERVICE_URL)
4
      .then(response => this.setState({quotes: response.data, 
5
                                       isFetching: false}))
6
      .catch(e => console.log(e);
7
  }

This is very similar, but a little more concise. The submit logic can be as simple as seen below.































1
handleSubmit = event => {
2
    axios.post(this.props.quote_service_url, 
3
               {'quote': this.state.quote})
4
      .then(r => console.log(r))
5
      .catch(e => console.log(e));
6
    event.preventDefault();
7
  }

With this basic introduction to Axios, let's learn more about the differences between the two libraries.


Differences between Axios and Fetch


JSON Data Transformation


If you look at Axios, the syntax appears as below. Axios takes care of converting the data to JSON



















































1
const url = ''
2
const data = {};
3
axios
4
  .post(url, data, {
5
    headers: {
6
      Accept: "application/json",
7
      "Content-Type": "application/json;charset=UTF-8",
8
    },
9
  })
10
  .then(({data}) => {
11
    console.log(data);
12
});

On the other hand, the basic syntax of fetch is as below. With fetch, you need to convert the data to a string, using JSON.stringify.



























































1
const url = "";
2
const options = {
3
  method: "POST",
4
  headers: {
5
    Accept: "application/json",
6
    "Content-Type": "application/json;charset=UTF-8",
7
  },
8
  body: JSON.stringify({}),
9
};
10
fetch(url, options)
11
  .then((response) => response.json())
12
  .then((data) => {
13
    console.log(data);
14
  });

Also, the response must be converted back to JSON with fetch


Response Timeout With Axios


In the example above, we had to implement logic whereby the API endpoint gets called after a predefined timeout duration. This is a major reason why fetch is avoided in real time applications. Axios makes response timeout extremely simple. This is an optional property in the config object of Axios. 



































1
axios({
2
  method: 'post',
3
  url: '',
4
  timeout: 5000,    
5
  data: {}
6
})
7
.then(response => {/* handle the response */})
8
.catch(error => console.error('timeout exceeded'))

Interceptors


One of the main reasons why developers prefer Axios over fetch is access to HTTP interceptors. By definition, HTTP interceptors are useful when you want to change, or inspect a HTTP request. The code does not have to be separated for every request, when you use interceptors. HTTP interceptors give a global strategy for handling requests, and responses. 


So, how do we achieve HTTP interception with Axios? Here is a snippet to help you. 











































1
axios.interceptors.request.use(config => {
2
  console.log('Hello There!');
3
  return config;
4
});
5

6
// sent a GET request

7
axios.get('')
8
  .then(response => {
9
    console.log(response.data);
10
  });

In the above piece of code, axios.interceptors.request.use method is used to tell the application what has to be done before firing the request. This would be a great place to inject authentication information into the request. 


On the other hand, code can become very complicated when you want to intercept a fetch request. You have to override the global implementation of fetch to define interceptors. And this is not an easy, or a clean task.


Simultaneous Requests


In a real time app, you will need a solution that can send multiple requests simultaneously. This is where Axios proves to be useful. The Axios library comes with many methods like all() and spread() to handle multiple requests. Here is a simple example, to help you understand how multiple requests can be sent in axios.


Here, the console.log statements will print only after both the API requests have completed successfully. 



































1
axios.all([
2
  axios.get('https://'), 
3
  axios.get('https://')
4
])
5
.then(axios.spread((a, b) => {
6
  console.log(a);
7
  console.log(b);
8
}));

To achieve the above logic in fetch, you have to make use of Promise.all. Let us translate the above logic into a fetch request.























































1
Promise.all([
2
  fetch('https://'),
3
  fetch('https://')
4
])
5
.then(async([res1, res2]) => {
6
  const a = await res1.json();
7
  const b = await res2.json();
8
  console.log(a');

9
  console.log(b');
10
})
11
.catch(error => {
12
  console.log(error);
13
});

Conclusion


In this post, you have seen many interesting facts, and ways of implementing of API requests in a React Application.


You have learnt how to fetch data asynchronously in a React application. And, we also discussed relevant lifecycle methods, polling, progress reporting, and error handling. We also compared the two main promise-based libraries: the Fetch API and Axios.


This post was updated with contributions from Divya Dev.



Original Link: https://code.tutsplus.com/tutorials/fetching-data-in-your-react-application--cms-30670

Share this article:    Share on Facebook
View Full Article

TutsPlus - Code

Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.

More About this Source Visit TutsPlus - Code