preface

Retrieving data asynchronously from the server and rendering it is a fairly frequent operation in daily development. We’re familiar with the React Class component, which uses Ajax to fetch data and setState in the Class component’s componentDidMount to trigger component updates.

With the advent of hooks, we can use the Hook notation instead of the Class notation in some scenarios. But Hook does not have setState, componentDidMount and other functions, and how to achieve asynchronous data from the server and render? This article will show you how to use React’s new Hook feature to write components and get data renders.

Data rendering

Let’s start with a simple demo of data rendering

import React, { useState } from 'react';
 
function App() {
  const [data, setData] = useState({ products: [{
	productId: '123'.productName: 'macbook'}}]);return (
    <ul>
      {data.products.map(i => (
        <li key={i.productId}>
          {i.productName}
        </li>
      ))}
    </ul>
  );
}
 
export default App;
Copy the code

In the demo, an internal state called Data is created with useState, which holds product data in a product list data. The App component uses products in data to render the product list data to the page.

But now it is a dead data, if we expect to fetch data from the server side and render, then we need to fetch the server side data when the component rendering is complete, and then change the state to trigger the render through setData. We’re going to use Axios to get the data.

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ products: [{
	productId: '123'.productName: 'macbook'}}]); useEffect(async() = > {const result = await axios(
      'https://c.com/api/products?date=today',); setData(result.data); });return (
    <ul>
      {data.products.map(i => (
        <li key={i.productId}>
          {i.productName}
        </li>
      ))}
    </ul>
  );
}
 
export default App;
Copy the code

UseEffect used in the code is one of the hooks, called Effect Hook. UseEffect is triggered every time a component is rendered, and we use it to fetch data and update state. But the above code is flawed, did you find it?

That’s right, as soon as you run it, you’ll find that the program goes into an endless loop. UseEffect is triggered not only when the component didMounts, but also when didUpdate is used. After getting data in useEffect, change state through setDate to trigger component rendering update, and enter useEffect again for an infinite loop. That’s not what we want. So what we want at first, we just want to get data at didMounts. So, in this case, we must pass a null [] to the second argument of the useEffect method so that the logic in useEffect is executed only when the component didMounts.

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ products: [{
	productId: '123'.productName: 'macbook'}}]); useEffect(async() = > {const result = await axios(
      'https://c.com/api/products?date=today',); setData(result.data); } []);/ / the key
 
  return (
    <ul>
      {data.products.map(i => (
        <li key={i.productId}>
          {i.productName}
        </li>
      ))}
    </ul>
  );
}
 
export default App;
Copy the code

Although this seems to be a low-level mistake, it is a common problem that many people make when they are new to hooks.

Of course, useEffect, the second argument, can also be passed a value. UseEffect is triggered when the values are updated when they are present. If it’s an empty array, it only fires on didMounts.

Promises and useEffect(async () =>…) Are not supported, but you can call an async function inside an effect. So if you want to use async, you need to change the way you write it.

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ products: [{
	productId: '123'.productName: 'macbook'}}]); useEffect(() = > {
  	const fetchData = async() = > {const result = await axios(
	      'https://c.com/api/products?date=today',); setData(result.data); } fetchData(); } []);return (
    <ul>
      {data.products.map(i => (
        <li key={i.productId}>
          {i.productName}
        </li>
      ))}
    </ul>
  );
}
 
export default App;
Copy the code

Experience optimization

In common applications, loading is added to the interaction design of some request processes to relieve user anxiety. How to implement Hook? It will be described below.

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ products: [{
	productId: '123'.productName: 'macbook'}}]);const [isLoading, setIsLoading] = useState(false);
 
  useEffect(() = > {
  	const fetchData = async()=>{
  		setIsLoading(true);
	  	const result = await axios(
	      'https://c.com/api/products?date=today',); setData(result.data); setIsLoading(false);
  	}
 	fetchData();
  },[]); 
 
  return (
  {isLoading ? (
        <div>Loading ...</div>
      ) : (
    <ul>
      {data.products.map(i => (
        <li key={i.productId}>
          {i.productName}
        </li>
      ))}
    </ul>
  )};
}
 
export default App;
Copy the code

This is done by adding a state called isLoading. We change the value of isLoading at the beginning and end of fetch to control the component content returned by return, thus displaying the Loading component before the request and the product list after the request.

Error handling

The requested process often fails for various reasons, such as network, server errors, and so on. So error handling is essential.

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ products: [{
	productId: '123'.productName: 'macbook'}}]);const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
 
  useEffect(() = > {
  	const fetchData = async()=>{
  	    setIsError(false);
  		setIsLoading(true);

		try{
			const result = await axios(
		      'https://c.com/api/products?date=today',); setData(result.data); }catch(e){
			setIsError(true);
		}
	    setIsLoading(false);
  	}
 	fetchData();
  },[]); 
 
  return (
  <div>
	{isError && <div>Make a mistake...</div>}
	{isLoading ? (
        <div>Loading ...</div>
      ) : (
    <ul>
      {data.products.map(i => (
        <li key={i.productId}>
          {i.productName}
        </li>
      ))}
    </ul>
  )};
  </div>
  
}
 
export default App;
Copy the code

When the request goes wrong, isError is set to true and the error component is rendered when the rendering is triggered. The processing here is simpler, and in a real world scenario you can add more complex logic to error handling. IsError is reset every time a hook is run.

The last

Now you have basically learned how to use React Hooks to get data and render components.

The blog was first published at github.com/SugarTurboS… Welcome your attention.