NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 5 - Hooky v Reactu - useState(), useEffect() a useRef()

V předchozí lekci, Serverové renderování podruhé - Stylování v Tailwind CSS, jsme dokončili serverové renderování a naši aplikaci nastylovali pomocí Tailwind CSS.

V dnešním tutoriálu pokročilého Reactu se blíže seznámíme s hooky a na praktickém příkladu si ukážeme, jak s nimi pracovat. Zaměříme se na použití hooků useState(), useEffect() a useRef().

Co jsou to hooky

Hooky jsou funkce, které poskytuje React jako součást jeho API, a umožňují funkčním komponentám manipulovat s funkcionalitami, které byly dříve dostupné pouze pro třídové komponenty. Hooky byly představeny v Reactu od verze 16.8 a znamenaly velkou změnu ve způsobu psaní komponent.

S hooky můžeme do funkčních komponent přidávat různé funkcionality a chování. Například useState() slouží pro ukládání stavu, useEffect() pro práci s efekty a useRef() pro vytváření referencí na DOM prvky nebo jiné hodnoty v komponentě.

Pro práci s hooky existuje několik pravidel. Hooky musejí být volány pouze na nejvyšší úrovni funkční komponenty nebo v jiných vlastních hook funkcích. Hooky naopak nemohou být volány v rámci podmínek, smyček nebo vnořených funkcí. Nemohou být volány ani v rámci třídových komponent. V těch je správným způsobem používání metod jako componentDidMount() nebo componentDidUpdate().

Hook useState()

Tato funkce umožňuje komponentám ukládat a aktualizovat svůj vnitřní stav. Stav je zachován mezi re-rendery komponenty, což umožňuje uchovávat data a interagovat s nimi v průběhu života komponenty.

Inicializace stavu využívá destrukturalizaci pole hodnot, které funkce useState() vrací. Vypadá takto:

const [stateVariable, setStateVariable] = useState(0);
  • stateVariable je proměnná, do které je uložena aktuální hodnota stavu. Při prvním renderování je to hodnota zadaná jako výchozí stav v závorce useState(), v našem příkladu 0.
  • setStateVariable() je funkce, kterou použijeme k aktualizaci stavu. Název funkce může být libovolný, ale konvence je používat slovo set následované názvem stavu.

Důležitým poznatkem je to, že volání funkce pro změnu stavu nezmění současný stav v kódu, který je právě vykonávaný. Ovlivní pouze to, co funkce useState() vrátí jako proměnnou od následujícího renderování:

const [name, setName] = useState("Jiří");

function handleClick() {
    setName("Adam");
    console.log(name); // Pořád Jiří!
}

Funkce jako výchozí stav

Jako inicializační stav pro useState() lze použít také funkci. To je užitečné v situaci, kdy je počáteční stav komponenty závislý na výpočtech nebo externím chování. Funkce pro inicializaci stavu se spustí pouze jednou, když se komponenta poprvé vykreslí. Funkce musí být čistá (pure), neměla by přijímat žádné argumenty a měla by vracet hodnotu libovolného typu:

const [stateVariable, setStateVariable] = useState(() => new Date().getSeconds());

Aktualizace stavu závislého na předchozím stavu

Pro aktualizaci stavu v Reactu, kdy nová hodnota závisí na předchozím stavu, je důležité zajistit, že aktualizace bude prováděna atomicky a spolehlivě. Toho dosáhneme pomocí funkce, která akceptuje předchozí stav jako argument:

setStateVariable((prevState) => prevState + 1);

Hook useEffect()

Hook useEffect() umožňuje provádět efekty v reakci na změny stavu nebo životní cyklus komponenty. Vedlejší efekt se spouští po vykreslení komponenty nebo když dojde ke změně některé ze závislostí.

Inicializace hooku vypadá takto:

useEffect(() => {
    console.log("efekt proběhl") // Kód pro efekt
}, [pole závislostí]);
  • Prvním argumentem je funkce, která obsahuje kód, který se má provést při spuštění efektu.
  • Druhým argumentem je pole závislostí (dependencies), které určuje, na co efekt reaguje. Pokud je prázdné, efekt se spustí pouze při prvním vykreslení komponenty a poté se už při změnách stavu nebo jiných faktorů znovu spouštět nebude. Pokud pole obsahuje závislosti, efekt se spustí pouze tehdy, změní-li se některá z těchto závislostí.

Pokud je pole závislostí prázdné, efekt bude fungovat jako metoda componentDidMount() v třídových komponentách.

Hook useRef()

Tento hook umožňuje referencovat a manipulovat s DOM elementy nebo jinými hodnotami uvnitř funkčních komponent.

Referenci vytvoříme pomocí useRef() a přiřazením do proměnné:

const myRef = useRef(0);

Referenci propojíme s DOM elementem tak, že ji přiřadíme atributu ref na elementu:

<input ref={myRef} />

Hook vrací objekt s jedinou vlastností. Nazývá se current. Vlastnost je prvotně nastavená na hodnotu, kterou jsme nastavili při vytvoření reference pomocí useRef(). V našem případě je to 0. Hodnotu pak lze libovolně měnit:

myRef.current = 1;

Pro přístup k hodnotě reference použijeme zápis myRef.current:

console.log(myRef.current);

Pro referenci je klíčové, že její změna nezpůsobuje opětovné renderování komponenty. Proto je vhodná k ukládání předchozích hodnot mezi renderováním. To znamená, že reference jsou ideální pro ukládání informací, které neovlivňují vizuál komponenty.

Reference by se také neměla číst nebo měnit v průběhu renderování:

return <h1>{myRef.current}</h1>; // 🚩 Tento kód není v pořádku!

Pokud v kódu potřebujeme referenci číst nebo měnit v průběhu renderování, je vhodné použít spíše stav pomocí hooku useState().

Čtení hodnoty reference nebo její změna jsou naopak v pořádku při obsluhování událostí. Například ve funkci s názvem clickHandler() nebo uvnitř funkce v hooku useEffect().

Praktická ukázka použití hooků

Teď si teorii vyzkoušíme v praxi. Hooky využijeme v aplikaci, kterou jsme vytvořili v lekci tohoto kurzu s názvem Vykreslování v Reactu a jeho optimalizace. Tam si také stáhneme z archivu kód aplikace, kterou společně rozšíříme. Naše aplikace bude nově obsahovat input, na který se vytvoří focus pokaždé, když bude Počet liché číslo:

Pokročilý React

Příprava projektu

Stažený projekt si otevřeme v preferovaném editoru kódu. V terminálu si spustíme příkaz pro instalaci modulů a projekt spustíme na lokálním serveru:

Instalace modulů a spuštění projektu:
npm install
npm run dev

Hook useState() v aplikaci

Hook useState() již v aplikaci využíváme. Pro zopakování si otevřeme soubor MainComponent.jsx a podíváme se na již napsaný kód:

import {useState} from 'react';
import MainCompChild from './MainCompChild';

function MainComponent() {
    console.log("hlavni komponenta");
    const [count, setCount] = useState(0);

    const incrementCount = () => {
        setCount((prevCount) => prevCount + 1); // Zvýší stav o 1 vzhledem k předchozímu stavu
    };

    return (
        <div style={{border: "2px solid"}}>
            <h2>Hlavní komponenta</h2>
            <p>Počet: {count}</p>
            <button onClick={incrementCount}>+</button>
            <MainCompChild />
        </div>
    )
}

export default MainComponent

Shrneme si to podstatné:

  • do souboru importujeme hook,
  • inicializujeme stav count s funkcí pro změnu setCount a počátečním stavem 0,
  • při kliknutí na tlačítko se spustí funkce incerementCount(), která zvýší stav proměnné count o 1 vzhledem k předchozímu stavu.

Přidání hooků useEffect() a useRef()

Teď společně do aplikace přidáme další dva hooky. Nejdříve si otevřeme soubor MainCompChild.jsx, s nímž budeme pracovat.

Do souboru přidáme import hooků:

import { useEffect, useRef } from "react";

Teď si pod console.log vytvoříme referenci:

const inputRef = useRef();

Nepotřebujeme výchozí hodnotu, jelikož referenci využijeme pro vytvoření reference na DOM prvek, konkrétně input. Tento input si teď do funkce přidáme pod <h3> ve vykreslovací části funkce:

<input type="text" placeholder="Focus při lichém počtu" ref={inputRef}></input>

Inputu přiřadíme vytvořenou referenci a v placeholderu vysvětlíme, čeho chceme docílit.

Pro hezčí vzhled přidáme přes inline styly margin divu, který obaluje vše, co funkce vrací:

<div style={{margin: 1 + "em"}}>

Teď potřebujeme zajistit, aby input získal focus pokaždé, když bude v proměnné count liché číslo. Na to je ideální hook useEffect(). Ten vykoná potřebné úkony pokaždé, když se změní proměnná count, kterou mu přidáme do pole závislostí.

Abychom znali aktuální stav proměnné count, posuneme si ji z rodičovské komponenty pomocí props. V souboru MainComponent.jsx nahradíme vykreslení <MainCompChild /> následujícím kódem:

<MainCompChild count={count} />

Vrátíme se zpět do souboru MainCompChild.jsx a v definici funkce jí přidáme props, přičemž si proměnnou count rovnou vytáhneme pomocí destrukturalizace:

function MainCompChild({count})

Za vytvoření reference pak přidáme následující kód:

useEffect(() => {
    if (count % 2 !== 0) {
        inputRef.current.focus();
    }
}, [count]);

Pokaždé když se změní hodnota proměnné count, funkce v prvním argumentu hooku ověří, jestli je současný počet lichý. Jestliže ano, zavolá metodu focus() na komponentu v DOM propojenou s naší referencí, tedy na input. Jde o jeden z mála případů, kdy je vhodné v Reactu přímo manipulovat s DOM elementy.

A to je všechno :) Když teď klikáme na tlačítko plus, při lichých hodnotách počtu získá input focus. V aplikaci teď využíváme všechny tři představené hooky.

V následující lekci, Hooky v Reactu - useCallback() a useMemo(), si vysvětlíme, jak fungují hooky useCallback() a useMemo(), a ukážeme si praktickou ukázku jejich využití.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 7x (46.4 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Předchozí článek
Serverové renderování podruhé - Stylování v Tailwind CSS
Všechny články v sekci
Pokročilý React
Přeskočit článek
(nedoporučujeme)
Hooky v Reactu - useCallback() a useMemo()
Článek pro vás napsala Laura Baluchová
Avatar
Uživatelské hodnocení:
14 hlasů
Aktivity