Jaké jsou hooky v Reactu?
sobes.tech AI
Odpověď od AI
V Reactu, od verze 16.8, hooky umožňují funkcionálním komponentám spravovat stav a používat životní cykly, které dříve byly dostupné pouze u třídových komponent.
Zde jsou hlavní vestavěné hooky:
-
useState: Umožňuje přidat vnitřní stav do funkčního komponentu. Vrací pár: aktuální stav a funkci pro jeho aktualizaci.// Příklad useState import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); // Inicializace stavu na 0 return ( <div> <p>Stiskli jste {count} krát</p> <button onClick={() => setCount(count + 1)}> Klikni na mě </button> </div> ); } -
useEffect: Umožňuje provádět vedlejší efekty v funkčních komponentách. Podobné metodám životního cyklu třídových komponent (componentDidMount,componentDidUpdate,componentWillUnmount).// Příklad useEffect import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Spouští se po každém renderu useEffect(() => { document.title = `Stiskli jste ${count} krát`; }); // Spouští se pouze při prvním renderu (prázdné pole závislostí) useEffect(() => { console.log('Komponenta byla namontována'); return () => { console.log('Komponenta byla odmontována'); // Čistící funkce }; }, []); // Spouští se při změně count useEffect(() => { console.log('Count se změnil:', count); }, [count]); return ( <div> <p>Stiskli jste {count} krát</p> <button onClick={() => setCount(count + 1)}> Klikni na mě </button> </div> ); } -
useContext: Umožňuje přihlásit se ke změnám kontextu React. Přijímá objekt kontextu vytvořený pomocíReact.createContext().// Příklad useContext import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); // Vytvoření kontextu function ThemedButton() { const theme = useContext(ThemeContext); // Použití kontextu return ( <button className={theme}> Tlačítko v tématu {theme} </button> ); } function App() { return ( <ThemedButton /> ); } -
useReducer: Alternativa kuseStatepro složitější správu stavu, který obsahuje více podhodnot nebo když závisí další stav na předchozím. Podobné reduktorům v Redux.// Příklad useReducer import React, { useReducer } from 'react'; const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> </> ); } -
useCallback: Memoizuje zpětné volání funkce. Vrací memoizovanou verzi callbacku, která se mění pouze při změně jedné ze závislostí. Užitečné pro zabránění zbytečnému přerenderování podkomponent při předávání callbacků.// Příklad useCallback import React, { useState, useCallback } from 'react'; function Parent({ addTodo }) { const [count, setCount] = useState(0); const handleAddTodo = useCallback(() => { addTodo(); }, [addTodo]); // závislost na addTodo return ( <> <button onClick={() => setCount(count + 1)}> Zvýšit čítač </button> <Child onAddItem={handleAddTodo} /> </> ); } function Child({ onAddItem }) { console.log('Child se renderuje'); // Bude se renderovat pouze při změně onAddItem return <button onClick={onAddItem}>Přidat položku</button>; } -
useMemo: Memoizuje vypočítanou hodnotu. Vrací memoizovanou hodnotu, která se přepočítává pouze při změně jedné ze závislostí. Užitečné pro výkon při náročných výpočtech.// Příklad useMemo import React, { useMemo, useState } from 'react'; function expensiveCalculation(num) { console.log('Probíhá nákladný výpočet...'); for (let i = 0; i < 1000000; i++) { num += 1; } return num; } function Example() { const [count, setCount] = useState(0); const [todos, setTodos] = useState([]); const calculation = useMemo(() => expensiveCalculation(count), [count]); // závislost na count const addTodo = () => { setTodos(t => [...t, "Nový úkol"]); }; return ( <div> <div> <h2>Moje úkoly</h2> {todos.map((todo, index) => ( <p key={index}>{todo}</p> ))} <button onClick={addTodo}>Přidat úkol</button> </div> <hr /> <div> Číslo: {count} <button onClick={() => setCount(c => c + 1)}>+</button> <h2>Nákladný výpočet</h2> {calculation} </div> </div> ); } -
useRef: Umožňuje vytvořit mutabilní odkaz, který přetrvává po celou dobu životnosti komponenty. Často se používá pro přístup k DOM elementům nebo uchovávání jakékoli mutabilní hodnoty, která nezpůsobí přerenderování při změně.// Příklad useRef import React, { useRef } from 'react'; function TextInputWithFocusButton() { const inputEl = useRef(null); // vytvoření odkazu const onButtonClick = () => { inputEl.current.focus(); // zaměření na DOM element }; return ( <> <input ref={inputEl} type="text" /> // přiřazení odkazu <button onClick={onButtonClick}>Zaostřit na pole</button> </> ); } -
useImperativeHandle: Nastavuje descriptor instance, který je poskytován rodičovskému komponentu při použitíref. Umožňuje dětskému komponentu odhalit určité metody rodiči. Používá se společně sforwardRef.// Příklad useImperativeHandle import React, { useRef, useImperativeHandle, forwardRef } from 'react'; const MyInput = forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focusInput: () => { inputRef.current.focus(); } })); return <input ref={inputRef} {...props} />; }); function ParentComponent() { const inputRef = useRef(); const handleFocus = () => { inputRef.current.focusInput(); // volání metody z dětského komponentu }; return ( <div> <MyInput ref={inputRef} /> <button onClick={handleFocus}>Zaostřit přes Parent</button> </div> ); } -
useLayoutEffect: Stejný jakouseEffect, ale běží synchronně po všech mutacích DOM. Užitečné pro čtení dat z DOM nebo provádění mutací, které musí být před vykreslením. Může blokovat renderování.// Příklad useLayoutEffect import React, { useLayoutEffect, useRef } from 'react'; function Tooltip({ children, text }) { const ref = useRef(null); useLayoutEffect(() => { if (ref.current) { const { top, height } = ref.current.getBoundingClientRect(); console.log(`Prvek je na ${top} s výškou ${height}`); } }, [children]); return ( <span ref={ref} title={text}> {children} </span> ); } -
useDebugValue: Zobrazí uživatelskou značku pro hooky v React DevTools. Používá se v vlastních hookách pro ladění.// Příklad useDebugValue import React, { useState, useDebugValue } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); // Zobrazí "Friend Status: Offline" nebo "Friend Status: Online" v DevTools useDebugValue(isOnline === true ? 'Online' : 'Offline'); // ... logika získání stavu přítele return isOnline; } function FriendListItem({ friend }) { const isOnline = useFriendStatus(friend.id); return ( <li style={{ color: isOnline ? 'zelená' : 'černá' }}> {friend.name} - {isOnline ? 'Online' : 'Offline'} </li> ); }
Kromě vestavěných hooků existují také vlastní hooky (Custom Hooks). Jsou to JavaScriptové funkce, jejichž jména začínají na "use". Umožňují opakované použití logiky stavu mezi komponentami. Vlastní hook může volat jiné hooky.
// Příklad vlastního hooku
import { useState, useEffect } from 'react';
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth, window.innerHeight]);
useEffect(() => {
const handleResize = () => {
setSize([window.innerWidth, window.innerHeight]);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return size;
}
function MyComponent() {
const [width, height] = useWindowSize(); // použití vlastního hooku
return (
<p>Velikost okna: {width}x{height}</p>
);
}
Důležité pravidla pro hooky:
- Volat hooky pouze na vrchní úrovni React komponenty nebo vlastního hooku. Nevolat je uvnitř cyklů, podmínek nebo vnořených funkcí.
- Volat hooky pouze z funkčních komponent React nebo vlastních hooků. Nevolat je z běžných JavaScriptových funkcí nebo metod třídních komponent.