Hook useState - Hướng dẫn toàn diện về Thông tin dữ liệu PlatoBlockchain. Tìm kiếm dọc. Ái.

The useState hook - Hướng dẫn toàn diện

Trạng thái là gì?

Trước khi đi sâu vào useState hook, trước tiên hãy hiểu thuật ngữ nhà nước.

State đại diện cho thông tin về một cái gì đó tại một thời điểm nhất định.

Ví dụ, hãy xem xét một hộp văn bản.

Ban đầu, không có gì bên trong hộp văn bản này, vì vậy trạng thái của nó là trống. Giả sử bạn bắt đầu nhập Hello bên trong nó, đối với mỗi hành trình phím, trạng thái của hộp văn bản sẽ thay đổi. Lúc đầu, nó sẽ là “H”, sau đó là “He”, sau đó là “Hel”, v.v. cho đến khi nó trở thành “Hello”.

Ngoài ra, hãy lưu ý rằng khi bạn đang nhập, bạn không bị mất giá trị trước đó. Nếu bạn nhấn “H” sau đó là “e”, bạn đang nhận được “He” chứ không chỉ “e”. Nói cách khác, bạn có thể nghĩ về trạng thái là trí nhớ của hộp văn bản.

Sự cần thiết của trạng thái trong một thành phần React.

Hãy hiểu điều này với sự trợ giúp của một ví dụ.

Hộp mã không có trạng thái

Ở đây chúng tôi có một Số lượt truy cập thành phần hiển thị số lần nút Tăng được nhấp.

Chúng tôi đang sử dụng một biến cục bộ "bộ đếm" để giữ số lần nhấp chuột.

Mỗi lần chúng ta nhấp vào nút Tăng dần, xử lý hàm sẽ được gọi. Hàm này sẽ tăng giá trị bộ đếm lên 1 và cũng ghi giá trị trong bảng điều khiển.

Hãy tiếp tục, nhấp vào nút Tăng trong bản xem trước CodeSandbox.

Không có chuyện gì xảy ra?

Vâng, logic của chúng tôi dường như là đúng. Giá trị được đăng nhập trong bảng điều khiển (CodeSandbox) cập nhật chính xác mỗi khi chúng tôi nhấp vào, nhưng tại sao bản cập nhật này không được phản ánh trong giao diện người dùng?

Đó là do cách hoạt động của React.

  • Các thay đổi đối với các biến cục bộ không kích hoạt kết xuất lại.
  • Trong quá trình kết xuất lại, một thành phần được tạo từ đầu, tức là chức năng của một thành phần (trong ví dụ này là hàm ClickCounter) được thực thi một lần nữa. Vì các biến (ví dụ, bộ đếm) là cục bộ của hàm, các giá trị trước đó của chúng sẽ bị mất.

Vì vậy, làm thế nào để chúng ta làm cho thành phần ghi nhớ các giá trị giữa các lần hiển thị?

Vâng, bạn đã hiểu đúng! Chúng tôi làm điều này với sự trợ giúp của sử dụngState móc.

Móc sử dụng

Móc useState cung cấp các cơ chế để duy trì trạng thái và kích hoạt kết xuất lại.

Hãy xem cách sử dụng của nó.

import React, { useState } from "react";
const state = useState(initialValue);

// OR

const state = React.useState(initialValue);

Móc useState trả về một mảng chứa hai mục:

  • A biến số đưa ra mà vẫn giữ nguyên các giá trị của nó trong khi kết xuất. Giá trị ban đầu được truyền cho useState được gán cho biến trạng thái trong lần hiển thị đầu tiên.
  • A chức năng setter cập nhật biến trạng thái và cũng kích hoạt kết xuất lại.
const state = useState(0);
const data = state[0];
const setData = state[1];

Sử dụng hủy cấu trúc mảng , chúng ta có thể cấu trúc lại các câu lệnh trên thành một câu lệnh duy nhất, như được hiển thị bên dưới:

const [data, setData] = useState(0);

Giá trị ban đầu được truyền cho useState chỉ được sử dụng trong lần hiển thị đầu tiên. Đối với kết xuất, nó bị bỏ qua.

Bộ đếm với useState

Bây giờ, hãy cập nhật ví dụ bộ đếm trước đó để bao gồm hook useState.

  • Vì chúng ta cần giá trị bộ đếm giữa các lần hiển thị, hãy chuyển nó thành trạng thái.
const [counter, setCounter] = useState(0);
  • Gọi setCounter bên trong hàm handleClick.
const handleClick = () => {
  setCounter(counter + 1);
  console.log(`%c Counter:${counter}`, "color:green");
};

Hàm setCounter sẽ cập nhật giá trị bộ đếm lên 1 và kích hoạt kết xuất lại. Khi hàm của thành phần được gọi khi kết xuất lại, biến trạng thái do useState trả về sẽ có giá trị cập nhật.

Hãy dùng thử CodeSandbox với mã được cập nhật. Nhấp vào nút Tăng dần và xem sự kỳ diệu của useState trong hoạt động.

Codesanbox với useState

Bạn có thể xác minh rằng khi kết xuất lại, thành phần chức năng Số lượt truy cập được gọi lại bằng cách xem nhật ký bảng điều khiển. Nhật ký “ClickCounter start” được thêm vào đầu thành phần sẽ được ghi vào mỗi lần hiển thị.

kết xuất đầu tiên

kết xuất lại

Chức năng cập nhật

Giả sử chúng ta muốn tăng giá trị của bộ đếm lên 4 trên mỗi lần nhấp chuột.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };

Giả sử rằng giá trị ban đầu của bộ đếm là 0. Bạn sẽ thấy gì sau khi bấm vào nút?

Không có chức năng cập nhật

Bạn mong đợi số đếm là 4 phải không? Nhưng tại sao bạn lại thấy 1 thay thế?

a) Mỗi ​​kết xuất được liên kết với một trạng thái. Giá trị của trạng thái đó vẫn bị khóa trong thời gian tồn tại của kết xuất đó.

Lưu ý rằng nhật ký bên trong hàm handleClick in giá trị bộ đếm là 0.

Bất kể bạn gọi phương thức setCounter bao nhiêu lần, giá trị của bộ đếm vẫn không đổi.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };
b) Cho đến khi tất cả mã bên trong trình xử lý sự kiện được thực thi, React sẽ không kích hoạt kết xuất lại.

Vì lý do này, mỗi lệnh gọi setCounter không kích hoạt một kết xuất riêng lẻ. Thay vào đó, React thêm các hàm setter này vào một hàng đợi. Thực hiện chúng theo thứ tự mà chúng đã được xếp hàng đợi. Các cập nhật được thực hiện cho trạng thái sau khi thực hiện tất cả các câu lệnh được phản ánh trong lần hiển thị tiếp theo. Hàng đợi nhiều cập nhật trạng thái này được gọi là trạm trộn. Nó cho phép React hoạt động hiệu quả hơn.

Do đó, ở đây chúng tôi nhận được một kết xuất duy nhất thay vì 4 kết xuất khác nhau.

Ví dụ này rất đơn giản và bạn có thể khắc phục sự cố này bằng cách cập nhật mã như được hiển thị bên dưới:

const handleClick = () => {
setCounter(counter + 4);
    console.log(`%c Counter:${counter}`, "color:green");
    };

Nhưng điều gì sẽ xảy ra nếu bạn gặp trường hợp sử dụng mà bạn muốn cập nhật trạng thái nhiều lần trước khi kết xuất tiếp theo.

Đó là nơi _ cập nhật _ chức năng đi kèm tiện dụng.

Chúng ta có thể cấu trúc lại ví dụ trước bằng chức năng cập nhật như sau:

const handleClick = () => {
  setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    setCounter(prevCounter => prevCounter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };

Đây Bộ đếm trước ⇒ Bộ đếm trước + 1 đại diện cho chức năng cập nhật.

Như đã giải thích trước đó, các câu lệnh của trình cập nhật này cũng được xếp hàng đợi (theo lô).

Hàm updater nhận một trạng thái đang chờ xử lý / trước đó mà nó sử dụng để tính toán trạng thái tiếp theo.

Chức năng cập nhật theo lô

Dưới đây là CodeSandbox với chức năng cập nhật được thêm vào. Hãy thử nhấp vào nút tăng dần.

Hộp cát chức năng của trình cập nhật

Chức năng khởi tạo

Hãy xem ví dụ dưới đây. Ở đây chúng ta đang gọi hàm getItems để lấy giá trị ban đầu cho trạng thái.

import React from "react";
import { useState } from "react";
function ListItems() { 
  const getItems = () => { 
    console.log(`%c getItems called`, "color:hotpink");
    	return Array(50).fill(0); 
    }; 
  const [items, setItems] = useState(getItems()); 
    
    return ( 
    	<div className="card">
        <ul> {items.map((item, index) => 
        	( <li key={index}>Item {index + 1}		</li>))} 
        </ul> <button onClick={() => setItems([...items, 0])}>Add Item</button> 	</div> );
} 
export default ListItems;

Hàm này tạo một mảng với kích thước 50 và điền vào mảng bằng các số không. Tham khảo hình ảnh bên dưới.

Mảng chứa 50 số không

Các mục này sau đó được hiển thị trên màn hình.

Mọi thứ có vẻ ổn nhưng chúng tôi có một vấn đề ở đây.

Click vào Thêm mặt hàng (nằm sau danh sách các mục) để thêm một mục mới vào danh sách. Quan sát các bản ghi.

Không có chức năng khởi tạo

Bạn có thấy vấn đề ở đây không?

Nhật ký "getItems được gọi là" được thêm vào bảng điều khiển mỗi khi bạn thêm một mục. Điều này có nghĩa là hàm này đang được gọi trên mỗi lần kết xuất.

Hãy nhớ rằng useState bỏ qua giá trị ban đầu được truyền cho nó sau lần hiển thị đầu tiên, nhưng ở đây giá trị ban đầu vẫn đang được tính toán lại. Điều này có thể tốn kém nếu chúng ta đang tạo các mảng lớn hoặc thực hiện các phép tính nặng.

Chúng tôi có thể giải quyết vấn đề này bằng cách vượt qua lấy vật phẩm như một _ người khởi tạo _ hàm số.

Bây giờ, hãy thực hiện một thay đổi nhỏ đối với mã.

const [items, setItems] = useState(getItems);

Với chức năng khởi tạo

Xem cửa sổ bảng điều khiển trong CodeSandbox. Lưu ý rằng nhật ký "getItems được gọi là" chỉ được in trong lần hiển thị đầu tiên. Khi các mục tiếp theo được thêm vào, nhật ký này không có ở đó.

Mặc dù không có sự khác biệt trực quan giữa hai ví dụ, nhưng về mặt hiệu suất, chúng khác nhau.

Hãy nhớ khi bạn cần một hàm cho trạng thái ban đầu, hãy luôn chuyển hàm hoặc gọi hàm bên trong một hàm khác. Không bao giờ gọi hàm trực tiếp.

✅ const [items, setItems] = useState(getItems);
✅ const [items, setItems] = useState(() => getItems());
❌ const [items, setItems] = useState(getItems());

Tôi có thể có bao nhiêu useState hooks

Bạn có thể có nhiều hook useState bên trong một thành phần tùy theo yêu cầu của nó.

Xem CodeSandbox

Sử dụng nhiều lần

Thành phần bên dưới có ba trạng thái khác nhau - tên người dùng, mật khẩu, keepMeSignedIn.

Hãy thử cập nhật các giá trị của tên người dùng, keepMeSignedIn. Các trạng thái cập nhật được ghi vào bảng điều khiển khi nhấp vào nút đăng nhập.

Điểm nổi bật

  • useState cung cấp một cơ chế để kích hoạt kết xuất lại và duy trì trạng thái giữa các kết xuất.
  • Sử dụng chức năng trình cập nhật khi bạn cần:
    • Tính toán trạng thái tiếp theo dựa trên trạng thái trước đó.
    • Thực hiện nhiều cập nhật cho trạng thái trước khi kết xuất tiếp theo.
  • Nếu trạng thái ban đầu được lấy từ một hàm - hãy sử dụng cú pháp hàm khởi tạo.
  • Có thể có nhiều useState hooks bên trong một thành phần.

Thích bài viết này? Chia sẻ nó với những người khác.
Được viết nguyên bản cho blog cá nhân của tôi - https://gauravsen.com/use-state-hook

Dấu thời gian:

Thêm từ Sự thật về phản ứng của Codementor