Hak useState - kompleksowy przewodnik PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Hak useState – obszerny przewodnik

Czym jest państwo?

Zanim zagłębimy się w temat hooka useState, najpierw zrozummy to pojęcie stan.

Stan reprezentuje informacje o czymś w danym momencie.

Rozważmy na przykład pole tekstowe.

Początkowo w tym polu tekstowym nie ma nic, więc jego stan to pusty. Załóżmy, że zaczniesz pisać w nim Hello, po każdym naciśnięciu klawisza zmieni się stan pola tekstowego. Na początku będzie to „H”, potem „He”, potem „Hel” i tak dalej, aż stanie się „Hello”.

Zauważ też, że podczas pisania nie tracisz poprzedniej wartości. Jeśli naciśniesz „H”, a następnie „e”, otrzymasz „He”, a nie tylko „e”. Innymi słowy, możesz myśleć o stanie jako pamięć pola tekstowego.

Potrzeba stanu w komponencie React.

Zrozummy to na przykładzie.

Codesanbox bez stanu

Tutaj mamy Licznik kliknięć komponent, który wyświetla liczbę kliknięć przycisku Przyrost.

Używamy zmienna lokalna „licznik” aby liczyć kliknięcia.

Za każdym razem, gdy klikamy przycisk Przyrost, uchwytKliknij zostanie wywołana funkcja. Ta funkcja zwiększy wartość licznika o 1, a także zarejestruje wartość w konsoli.

Śmiało, kliknij przycisk Przyrost w podglądzie CodeSandbox.

Nic się nie stało?

Cóż, nasza logika wydaje się słuszna. Wartość zarejestrowana w konsoli (CodeSandbox) aktualizuje się poprawnie za każdym razem, gdy klikamy, ale dlaczego ta aktualizacja nie jest odzwierciedlona w interfejsie użytkownika?

To ze względu na sposób działania Reacta.

  • Zmiany zmiennych lokalnych nie powodują ponownego renderowania.
  • Podczas ponownego renderowania komponent jest tworzony od podstaw, czyli funkcja komponentu (w tym przykładzie jest to funkcja ClickCounter) jest wykonywana ponownie. Ponieważ zmienne (na przykład licznik) są lokalne dla funkcji, ich poprzednie wartości są tracone.

Jak więc sprawić, by komponent zapamiętywał wartości między renderowaniami?

Tak, masz rację! Robimy to za pomocą stan użycia hak.

Hak useState

Hak useState udostępnia mechanizmy zachowania stanu i wyzwalania ponownego renderowania.

Przyjrzyjmy się jego wykorzystaniu.

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

// OR

const state = React.useState(initialValue);

Hook useState zwraca tablicę zawierającą dwa elementy:

  • A zmienna stanu który zachowuje swoje wartości podczas ponownego renderowania. Wartość początkowa przekazywana do useState jest przypisywana do zmiennej state podczas pierwszego renderowania.
  • A funkcja setera która aktualizuje zmienną stanu, a także wyzwala ponowne renderowanie.
const state = useState(0);
const data = state[0];
const setData = state[1];

Korzystanie z destrukturyzacja tablicy , możemy zrefaktoryzować powyższe stwierdzenia w pojedynczą instrukcję, jak pokazano poniżej:

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

Wartość początkowa przekazana do useState jest używana tylko podczas pierwszego renderowania. W przypadku ponownego renderowania jest ignorowany.

Licznik z useState

Teraz zaktualizujmy wcześniejszy przykład licznika, aby uwzględnić hak useState.

  • Ponieważ potrzebujemy wartości licznika między kolejnymi renderowaniami, przekształćmy ją w stan.
const [counter, setCounter] = useState(0);
  • Wywołanie setCounter wewnątrz funkcji handleClick.
const handleClick = () => {
  setCounter(counter + 1);
  console.log(`%c Counter:${counter}`, "color:green");
};

Funkcja setCounter zaktualizuje wartość licznika o 1 i wywoła ponowne renderowanie. Gdy funkcja komponentu zostanie wywołana podczas ponownego renderowania, zmienna stanu zwrócona przez useState będzie miała zaktualizowaną wartość.

Wypróbuj CodeSandbox ze zaktualizowanym kodem. Kliknij przycisk Przyrost i zobacz magię useState w akcji.

Codesanbox z useState

Możesz sprawdzić, czy przy ponownym renderowaniu komponent funkcjonalny Licznik kliknięć jest wywoływana ponownie, wyświetlając dzienniki konsoli. Dziennik „ClickCounter start”, który jest dodawany na początku komponentu, będzie rejestrowany przy każdym renderowaniu.

pierwsze renderowanie

ponownie render

Funkcja aktualizacji

Załóżmy, że chcemy zwiększać wartość licznika o 4 przy każdym kliknięciu.

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

Załóżmy, że początkowa wartość licznika wynosi 0. Co spodziewasz się zobaczyć po kliknięciu przycisku?

Bez funkcji aktualizacji

Spodziewałeś się, że liczba będzie wynosić 4, prawda? Ale dlaczego zamiast tego widzisz 1?

a) Każdy render jest powiązany ze stanem. Wartość tego stanu pozostaje zablokowana na czas trwania renderowania.

Zauważ, że dziennik wewnątrz funkcji handleClick wyświetla wartość licznika jako 0.

Bez względu na to, ile razy wywołasz metodę setCounter, wartość licznika pozostanie taka sama.

const handleClick = () => {
  setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    setCounter(counter + 1);
    console.log(`%c Counter:${counter}`, "color:green");
    };
b) Dopóki cały kod wewnątrz procedury obsługi zdarzeń nie zostanie wykonany, React nie wywoła ponownego renderowania.

Z tego powodu każde wywołanie setCounter nie wyzwala indywidualnego renderowania. Zamiast tego React dodaje te funkcje ustawiające w kolejce. Wykonuje je w kolejności, w jakiej były w kolejce. Aktualizacje wprowadzone do stanu po wykonaniu wszystkich instrukcji są odzwierciedlane w następnym renderowaniu. To kolejkowanie aktualizacji wielu stanów jest znane jako partie. Dzięki temu React jest bardziej wydajny.

Dlatego tutaj otrzymujemy pojedynczy render zamiast 4 różnych renderów.

Ten przykład jest prosty i możesz rozwiązać ten problem, aktualizując kod, jak pokazano poniżej:

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

Ale co by było, gdybyś miał przypadek użycia, w którym chciałbyś wielokrotnie aktualizować stan przed następnym renderowaniem.

To tam _ updater Przydaje się funkcja _.

Możemy dokonać refaktoryzacji poprzedniego przykładu za pomocą funkcji aktualizującej w następujący sposób:

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");
    };

Tutaj prevLicznik ⇒ prevLicznik + 1 reprezentuje funkcję aktualizacji.

Jak wyjaśniono wcześniej, te instrukcje aktualizacji są również umieszczane w kolejce (wsadowe).

Funkcja aktualizująca otrzymuje stan oczekujący/poprzedni, którego używa do obliczenia następnego stanu.

Dozowanie funkcji aktualizacji

Poniżej znajduje się CodeSandbox z dodaną funkcją aktualizatora. Spróbuj kliknąć przycisk przyrostu.

Piaskownica funkcji aktualizacji

Funkcja inicjatora

Spójrz na poniższy przykład. Tutaj wywołujemy funkcję getItems, aby uzyskać początkową wartość stanu.

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;

Ta funkcja tworzy tablicę o rozmiarze 50 i wypełnia ją zerami. Zobacz obrazek poniżej.

Tablica wypełniona 50 zerami

Te elementy są następnie wyświetlane na ekranie.

Wszystko wydaje się być w porządku, ale mamy tutaj problem.

Kliknij na Dodaj Przedmiot przycisk (znajdujący się za listą pozycji), aby dodać nową pozycję do listy. Obserwuj dzienniki.

Bez funkcji inicjatora

Czy widzisz tutaj problem?

Dziennik „getItems Called” jest dodawany do konsoli za każdym razem, gdy dodajesz element. Oznacza to, że ta funkcja jest wywoływana przy każdym renderowaniu.

Pamiętaj, że useState ignoruje wartość początkową przekazaną do niego po pierwszym renderowaniu, ale tutaj wartość początkowa jest wciąż ponownie obliczana. Może to być kosztowne, jeśli tworzymy duże tablice lub wykonujemy ciężkie obliczenia.

Możemy rozwiązać ten problem, przekazując zdobądź przedmioty jako _ inicjator _ funkcja.

Teraz zróbmy małą zmianę w kodzie.

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

Z funkcją inicjatora

Zobacz okno konsoli w CodeSandbox. Zauważ, że dziennik „getItems named” jest drukowany tylko przy pierwszym renderowaniu. Gdy dodawane są kolejne pozycje, tego dziennika nie ma.

Chociaż nie ma wizualnej różnicy między tymi dwoma przykładami, pod względem wydajności są one różne.

Pamiętaj, kiedy potrzebujesz funkcji dla stanu początkowego, zawsze przekaż funkcję lub wywołaj funkcję wewnątrz innej funkcji. Nigdy nie wywołuj funkcji bezpośrednio.

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

Ile mogę mieć hooków useState

Możesz mieć tyle haczyków useState wewnątrz komponentu, ile wymaga.

Zobacz CodeSandbox

Wiele haczyków useState

Poniższy komponent ma trzy różne stany – nazwa użytkownika, hasło, keepMeSignedIn.

Spróbuj zaktualizować wartości nazwy użytkownika, keepMeSignedIn. Zaktualizowane stany są rejestrowane w konsoli po kliknięciu przycisku logowania.

Najważniejsze

  • useState udostępnia mechanizm wyzwalania ponownego renderowania i utrzymywania stanu między kolejnymi renderowaniami.
  • Korzystaj z funkcji aktualizacji, gdy musisz:
    • Oblicz następny stan na podstawie stanu poprzedniego.
    • Wykonaj wiele aktualizacji stanu przed następnym renderowaniem.
  • Jeśli stan początkowy jest uzyskiwany z funkcji – użyj składni funkcji inicjującej.
  • Wewnątrz komponentu może znajdować się wiele haczyków useState.

Podobał Ci się ten post? Podziel się nim z innymi.
Oryginalnie napisany na mój osobisty blog – https://gauravsen.com/use-state-hook

Znak czasu:

Więcej z Codementor Reaguj na fakt