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 componentDidMount
và componentDidUpdate
.
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 .
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 .
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, componentDidMount
và componentDidUpdate
.
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.
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ủasetUsers
. -
showDetails
trạng tháishowDetails
được khởi tạo với giá trịfalse
và được gán chức năng củasetShowDetails
.
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 componentDidMount
và componentDidUpdate
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 ] );
Các tin liên quan