Thứ tư, 09/09/2020 | 00:00 GMT+7

Thay thế các Vòng đời Thành phần bằng việc sử dụng Effect Hook, trong React

React Hooks đang cách mạng hóa cách ta phát triển trong React và giải quyết một số mối quan tâm lớn nhất của ta . useEffect Hook cho phép ta thay thế mã vòng đời của thành phần lặp đi lặp lại.

Về cơ bản, Hook là một chức năng đặc biệt cho phép bạn “kết nối” các tính năng của React. Hooks là một giải pháp tuyệt vời nếu trước đây bạn đã viết một thành phần chức năng và nhận ra rằng bạn cần thêm trạng thái cho nó.

Nếu bạn chưa quen với Hooks và muốn có một cái nhìn tổng quan, hãy xem phần giới thiệu về React Hooks .

Bài viết này giả định bạn đã quen thuộc với useState Hook. Nếu bạn không, đừng bao giờ sợ hãi! Nếu bạn dành một chút thời gian cho việc Chuyển đổi một thành phần dựa trên lớp React thành một thành phần chức năng bằng cách sử dụng State Hook, bạn sẽ đi đúng hướng!

Giới thiệu về sử dụng

useEffect là viết tắt của 'sử dụng tác dụng phụ'. Hiệu ứng là khi ứng dụng của ta phản ứng với thế giới bên ngoài, giống như làm việc với một API. Nó cho phép ta chạy một chức năng dựa trên việc có gì đó thay đổi hay không. useEffect cũng cho phép ta kết hợp componentDidMountcomponentDidUpdate .

Về ứng dụng của ta

Ta sẽ lấy một số mã dựa trên lớp được viết sẵn và chuyển đổi nó thành một thành phần chức năng. Ta sẽ sử dụng reactstrap để đơn giản hóa định dạng và tiên đề của ta để gọi một API giả bên ngoài.

Cụ thể, ta đang sử dụng jsonplaceholder để lấy dữ liệu user giả trên mount thành phần ban đầu của ta .

Mã khởi động

Sau đó, ta sẽ kích hoạt thành phần hiển thị lại dựa trên một lần nhấp của user và lấy thêm dữ liệu về user .

Mã người mới bắt đầu, đã nhấp vào

Bắt đầu

Chỉ cần sao chép qua repo với mã bắt đầu:

$ git clone https://github.com/alligatorio/use-effect-hook $ npm i $ npm start 

Hãy dành một chút thời gian để tự làm quen với mã, cụ thể là file ClassBasedComponent.js .

Bạn sẽ nhận thấy rằng ta có hai phương thức vòng đời trong file này, componentDidMountcomponentDidUpdate .

async componentDidMount() {   const response = await axios     .get(`https://jsonplaceholder.typicode.com/users`);    this.setState({ users: response.data }); };  async componentDidUpdate(prevProps) {   if (prevProps.resource !== this.props.resource) {     const response = await axios       .get(`https://jsonplaceholder.typicode.com/users`);      this.setState({ users: response.data });   } }; 

Cả hai đều là async phương pháp vòng đời mà gọi API jsonplaceholder để mang lại một danh sách user .

Trong componentDidMount , ta nói trong lần hiển thị đầu tiên, hãy lấy dữ liệu user . Tiếp theo, trên componentDidUpdate ta xem xét liệu có gì thay đổi trong các props . Điều này có thể được kích hoạt từ các sự kiện do user khởi tạo, như trong ví dụ của ta , một lần nhấn nút. Khi ta phát hiện thay đổi, hãy ra ngoài và lấy lại dữ liệu .

Ta muốn cô đọng các phương thức vòng đời vào useEffect Hook và tạo một thành phần dựa trên chức năng.

Tạo một thành phần

Thay vì sử dụng cùng một file ClassBasedComponent.js , hãy tạo một file mới có tên là FunctionBasedComponent.js . Ta đang tạo một file mới để ta có thể đối chiếu và so sánh hai file .

Trong terminal của bạn, bạn có thể chạy như sau để tạo file mới từ folder root của bạn :

$ touch FunctionBasedComponent.js 

Để giúp bắt đầu, hãy copy paste mã bên dưới vào file mới của bạn:

import React, { useState, useEffect } from 'react'; import { Container, Button, Row } from 'reactstrap'; import axios from 'axios';  const FunctionBasedComponent = () => {   return (     <Container className="user-list">       <h1>My Contacts:</h1>     </Container>   ) };  export default FunctionBasedComponent; 

Bây giờ chuyển sang file App.js của bạn, nhập file FunctionBasedComponent.js của bạn và thay thế ClassBasedComponent bằng FunctionBasedComponent .

Ứng dụng của bạn bây giờ sẽ trông giống như ảnh chụp màn hình bên dưới.

ứng dụng bắt đầu sử dụng của  ta


Hãy bắt đầu bằng cách khởi tạo trạng thái với useState .

const [ users, setUsers ] = useState([]); const [ showDetails, setShowDetails ] = useState(false); 

Để tóm tắt nhanh về useState , để khởi tạo state với hook useState , ta khai báo cả biến và hàm tương ứng với biến trong một mảng và sau đó ta truyền đối số useState() mà ta muốn khởi tạo biến của ta .

  • Biến trạng thái users được khởi tạo bằng một mảng trống và được cung cấp chức năng của setUsers .
  • showDetails trạng thái showDetails được khởi tạo với giá trị false và được gán chức năng của setShowDetails .

Thêm một cuộc gọi API

Hãy tiếp tục và thêm vào lệnh gọi API của ta dưới dạng hàm fetchUsers .

const fetchUsers = async () => {   const response = await axios.get(`https://jsonplaceholder.typicode.com/users`);    setUsers(response.data); }; 

Ta đang thực chất kéo này async cuộc gọi từ các cựu componentDidMountcomponentDidUpdate chức năng.

Hãy nhớ ta không thể sử dụng một async chức năng trực tiếp bên useEffect . Nếu ta muốn gọi một hàm không đồng bộ, ta cần xác định hàm bên ngoài useEffect và sau đó gọi nó trong useEffect .

Đối số sử dụng

Hãy nói về hook useEffect một chút. Giống như componentDidMount , useEffect sẽ gọi ngay hàm của ta .

useEffect( () => {}, [ 'value' ]); 

Theo mặc định, useEffect sẽ xem các giá trị mảng có khác nhau hay không và nếu chúng khác nhau thì hàm mũi tên sẽ tự động được gọi.

useEffect( () => {}, [ 'different value' ]); 

Hãy quay lại trình soạn thảo mã của ta và thêm hook useEffect bên dưới hàm mới nhất của ta , nơi ta sẽ gọi là fetchUsers .

Trong đoạn mã bên dưới, ta đang xem xét đối tượng user để xem có thay đổi hay không.

useEffect( () => { fetchUsers(users) }, [ users ] ); 

Các vấn đề chung

  • Nếu bạn không chuyển một mảng vào useEffect Hook, thành phần của bạn sẽ liên tục reload nhiều lần.
useEffect( () => { fetchUsers(users) } ); 
  • Nếu bạn chuyển một mảng trống, ta sẽ không xem bất kỳ biến nào và do đó nó sẽ chỉ cập nhật trạng thái trong lần hiển thị đầu tiên, giống hệt như componentDidMount .
useEffect( () => { fetchUsers(users) }, [] ); 
  • Mỗi khi ta tạo một đối tượng trong JavaScript, nó sẽ là một đối tượng khác trong bộ nhớ. Mặc dù mã bên dưới trông giống nhau, nhưng trang sẽ được hiển thị lại vì mỗi đối tượng được lưu trữ trong một địa chỉ bộ nhớ khác nhau. Logic tương tự cũng áp dụng cho các mảng.
useEffect( () => { fetchUsers(users) }, [{ user: 'Alli Alligator' }] ); 

Không bằng!

useEffect( () => { fetchUsers(users) }, [{ user: 'Alli Alligator' }] ); 
  • useEffect phải trả về một hàm dọn dẹp hoặc không có gì.

Để chứng minh việc kích hoạt một kết xuất lại khác, hãy copy paste mã bên dưới vào file FunctionBasedComponent.js của bạn:

import React, { useState, useEffect } from 'react'; import { Container, Button, Row } from 'reactstrap'; import axios from 'axios';  const FunctionBasedComponent = () => {   const [ users, setUsers ] = useState([]);   const [ showDetails, setShowDetails ] = useState(false);    const fetchUsers = async () => {     const response = await axios.get(`https://jsonplaceholder.typicode.com/users`);      setUsers(response.data);   };    useEffect( () => { fetchUsers(users) }, [ users ] );    const handleClick = event => { setShowDetails(!showDetails) };    return (     <Container>       {         users.map((user) => (           <ul key={ user.id }>             <li>               <strong>{ user.name }</strong>               <div>                 <Button                   onClick={ handleClick }                 >                   { showDetails ? "Close Additional Info" : "More Info"  }               </Button>                { showDetails &&                  <Container className="additional-info">                    <Row>                      { `Email: ${ user.email }` }                    </Row>                    <Row>                      { `Phone: ${ user.phone }` }                    </Row>                    <Row>                      { `Website: ${ user.website }` }                    </Row>                  </Container>                }               </div>             </li>           </ul>         ))       }     </Container>   ) }  export default FunctionBasedComponent; 

Bây giờ ta có một sự kiện onClick trong một nút. Khi nhấp vào nút, trạng thái của showDetails được thay đổi, kích hoạt kết xuất lại sẽ gọi lại API và cung cấp các chi tiết bổ sung mà ta cần.

Voilà!

async componentDidMount() {     const response = await axios.get(`https://jsonplaceholder.typicode.com/users`)     this.setState({ users: response.data }) };  async componentDidUpdate(prevProps) {   if (prevProps.resource !== this.props.resource) {     const response = await axios.get(`https://jsonplaceholder.typicode.com/users`)     this.setState({ users: response.data })   } }; 

Trở thành:

const fetchUsers = async () => {   const response = await axios.get(`https://jsonplaceholder.typicode.com/users`);    setUsers(response.data); };  useEffect( () => { fetchUsers(users) }, [ users ] ); 

Tags:

Các tin liên quan