React hook là tính năng mới tuyệt vời trong React 16.8. Nó sẽ là tính năng mà chúng ta sẽ sử dụng hàng ngày để phát triển các dự án React.
Nếu bạn muốn sử dụng state
hoặc các phương thức lifecycle, bạn sẽ phải chuyển sang sử dụng React.Component
và các class. Hook cho phép chúng ta sử dụng trong functional component.
Hook là gì?
React hook là cách để thêm các tính năng của React.Component
vào các functional component. Các tính năng như sau:
- State
- Lifecycle
Hook cho phép chúng ta sử dụng các tính năng của React mà không cần sử dụng class
Mặc dù vậy, các class sẽ không bị xoá hoặc không được khuyến khích. Chúng ta đang được cung cấp thêm nhiều cách hơn để code
State của hook
Giả sử chúng ta có một component như sau:
State trong component
import React, { Component } from 'react'; class JustAnotherCounter extends Component { state = { count: 0 }; setCount = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <h1>{this.state.count}</h1> <button onClick={this.setCount}>Count Up To The Moon</button> </div> ); } }
Nhưng với React hook, chúng ta có thể viết ngắn gọn class bên trong functional component
State với functional component và useState
import React, { useState } from 'react'; function JustAnotherCounter() { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={() => setCount(count + 1)}>Count Up To The Moon</button> </div> ); }
Kết quả
Cú pháp useState() là gì?
Bạn có thể sẽ không quen với kiểu sử dụng cú pháp useState()
. Cái này sử dụng destructuring assignment cho các mảng. Điều này tương tự như cách chúng ta lấy các prop ra khỏi một object bằng object destructuring
Chúng ta hãy cùng so sánh object destructuring vs array destructuring để thấy rằng tại sao sử dụng mảng lại hữu ích.
Object destructuring đòi hỏi phải viết nhiều hơn để lấy một biến và đổi tên nó
Object Destructuring
// object destructuring. viết nhiều hơn const users = { admin: 'chris', user: 'nick' }; // lấy admin và user nhưng đổi tên thành SuperAdmin và SuperUser const { admin: SuperAdmin, user: SuperUser } = users;
Đoạn code bên dưới cùng hơi khó đọc, sử dụng array destructuring, chúng ta chỉ cần đặt tên biến và lấy giá trị tương ứng trong mảng. Biến đầu tiên là phần tử đầu tiên trong mảng.
Array Destructuring
// array destructuring const users = ['chris', 'nick']; // lấy gía trị và đổi tên const [SuperAdmin, SuperUser] = users;
useState là gì?
useState
cung cấp 2 biến và chúng ta có thể đặt tên bất kỳ cho 2 biến, chỉ biết rằng:
- Biến đầu tiên là giá trị, giống như
this.state
- Biến thứ 2 là hàm để cập nhập giá trị, giống như
this.setState
Tham số truyền vào cho useState
là giá trị khởi tạo. Trong ví dụ trên thì giá trị đếm được bắt đầu từ 0
Sử dụng nhiều State trong Hook
Chúng ta có thể sử dụng useState()
nhiều lần trong cùng một hàm
import React, { useState } from 'react'; function AllTheThings() { const [count, setCount] = useState(0); const [products, setProducts] = useState([{ name: 'Surfboard', price: 100 }]); const [coupon, setCoupon] = useState(null); return <div>{/_ thêm code vào đây _/}</div>; }
Effect React Hook
State Hook cho phép chúng ta sử dụng state
trong các component functional của React. Điều này giúp chúng ta tiến thêm một bước gần hơn sử dụng functional component thay cho class component.
Các Effect là tương tự như componentDidMount
, componentDidUpdate
và componentWillUnmount
Sau đây là một số đặc điểm của Effect Hook
- Lấy dữ liệu
- Cập nhập DOM thủ công (document title)
- Thiết lập một subcription
Effect sẽ chạy sau tất cả các render bao gồm cả render đầu tiên
Hãy so sánh một class với một functional component
import React, { Component } from 'react'; class DoSomethingCrazy extends Component { componentDidMount() { console.log('i have arrived at the party!'); document.title = 'preesent'; } render() { return <div>stuff goes here</div>; } }
Khi sử dụng Effect Hook, chúng ta dùng useEffect()
function DoSomethingCrazy() { useEffect(() => { console.log('i have arrived at the party!'); document.title = 'preesent'; }); return <div>stuff goes here</div>; }
Kết quả
stuff goes here
useEffect()
là hiệu quả không? Giống hệt như componentDidMount
và componentDidUpdate
Chỉ chạy Effect Hook khi có thay đổi
Do useEffect() chạy mỗi khi component render, vậy làm thế nào chúng ta chỉ chạy nó một lần khi mount? Effect Hook nhận tham số thứ 2, một mảng, nó sẽ kiểm tra mảng và chỉ chạy một lần một trong những giá trị trong đó thay đổi.
componentDidMount: Chạy một lần
// chỉ chạy khi mount, truyền vào mảng rỗng useEffect(() => { // only runs once }, []);
componentDidUpdate: Chạy khi có thay đổi
// Chỉ chạy khi count thay đổi useEffect( () => { // Chạy khi count thay đổi }, [count] );
Nếu bạn muốn chạy một vài thứ trước khi unmount, chúng ta chỉ cần trả về một hàm từ useEffect()
.
useEffect(() => { UsersAPI.subscribeToUserLikes(); // unsubscribe return () => { UsersAPI.unsubscribeFromUserLikes(); }; });
Sử dụng State và Effect cùng nhau
Sẽ không vó vấn đề gì khi sử dụng chúng cùng nhau. Chúng có thể cùng nhau tạo các functional component mà hoạt động giống như class component
Hãy cùng xem ví dụ trong thực tế sau đây: Chúng ta cần lấy danh sách người dùng từ Github sử dụng api với useEffect()
và đồng thời sử dụng useState()
. Đầu tiên chúng ta sử dụng useState()
import React, { useState } from 'react'; function GitHubUsers() { const [users, setUsers] = useState([]); }
Chúng ta khởi tạo users là một mảng rỗng bằng cách khai báo useState([])
. Tiếp theo chúng ta sẽ đưa vào trong Hook useEfffect()
và sử dụng fetch để lấy dữ liệu từ Github API.
import React, { useState } from 'react'; function GitHubUsers() { const [users, setUsers] = useState([]); useEffect(() => { fetch('https://api.github.com/users') .then(response => response.json()) .then(data => { setUsers(data); // gán dữ liệu cho users }); }, []); //mảng rổng vì chúng ta chỉ chạy một lần }
Chú ý rằng tham số thứ 2 của useEffect()
truyền vào một mảng rỗng bởi vì chúng ta chỉ muốn chạy một lần duy nhất. Cuối cùng hiển thị kết quả như sau
import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; function GitHubUsers() { return ( <div className="section"> {users.map(user => ( <div key={user.id} className="card"> <h5>{user.login}</h5> </div> ))} </div> ); }
Kết quả