Use React Hooks to request data and render

Preface

In daily development, obtaining and rendering data asynchronously from the server is a very high frequency operation. In the past when using React Class components, this operation is already familiar to us, that is, through ajax in the componentDidMount of the Class component to get the data and setState to trigger the component update.

With the advent of Hook, we can use Hook writing to replace Class writing in some scenarios. But there are no functions such as setState and componentDidMount in Hook. How can we obtain and render data asynchronously from the server? This article will introduce how to use React's new feature Hook to write components and get data rendering.

Data rendering

Let's first look at 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;

In the demo, dataan internal state is created through useState , in which there is a product list data to store product data. The App component renders the product list data to the page through the products in the data.

But now it is hard-coded data. If we expect to get the data from the server and render it, then we need to fetch the server data when the component rendering is complete, and then change the state to trigger the rendering through setData. We then prepared to use axiosto obtain 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;

What is used in the code useEffectis one of the hooks called effect hook. useEffect will be triggered every time the component renders, we use it to get data and update state. But the above code is flawed, have you found it?

Yes, as long as you run it, you will find that the program has entered an endless loop. Because useEffect is not only triggered when the component didMounts, but also when the component didUpdate. After the data is obtained in useEffect, the state is changed through setDate, which triggers the component rendering update, which enters the useEffect again, and the loop continues indefinitely. This is not the result we want. What we wanted at first was to get the data once during didMounts. Therefore, in this case, we must pass an empty [] to the second parameter of the useEffect method, so that the logic in useEffect is only executed 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);
  },[]);  //重点
 
  return (
    <ul>
      {
    
    data.products.map(i => (
        <li key={
    
    i.productId}>
          {
    
    i.productName}
        </li>
      ))}
    </ul>
  );
}
 
export default App;

Although it seems that this error is relatively low-level, it is indeed a problem that many people often make when they are new to hooking.

Of course, the second parameter of useEffect can also be passed in a value. When there are values, useEffect will trigger when these values ​​are updated. If it is just an empty array, it will only trigger when didMounts.

In addition, the implementation of this code, you'll see the console warning 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 modify the wording.

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;

Experience optimization

In general applications, loading is added to the interaction design of certain request processes to relieve user anxiety. How to implement it in the writing of Hook? It will be introduced 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;

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

Error handling

The request process often fails due to various reasons, such as network and server errors. 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>出错了...</div>}
	{
    
    isLoading ? (
        <div>Loading ...</div>
      ) : (
    <ul>
      {
    
    data.products.map(i => (
        <li key={
    
    i.productId}>
          {
    
    i.productName}
        </li>
      ))}
    </ul>
  )};
  </div>
  
}
 
export default App;

When there is an error in the request, it isErrorwill be set to true. When the rendering is triggered, the error notification component will be rendered. The processing here is relatively simple. In a real scenario, you can add more complex logic to error handling. isErrorIt will be reset every time the hook runs.

At last

After reading this, you have basically learned how to use React Hooks to get data and render components.

Guess you like

Origin blog.csdn.net/ForeverCjl/article/details/109124199