Jakie są hooki w React?
sobes.tech AI
Odpowiedź od AI
W React, od wersji 16.8, hooki zapewniają komponentom funkcyjnym możliwość zarządzania stanem i korzystania z cykli życia, które wcześniej były dostępne tylko dla komponentów klasowych.
Oto główne wbudowane hooki:
-
useState: Pozwala dodać stan wewnętrzny do komponentu funkcyjnego. Zwraca parę: aktualny stan i funkcję do jego aktualizacji.// Przykład useState import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); // Inicjalizacja stanu z 0 return ( <div> <p>Naciśnięto {count} razy</p> <button onClick={() => setCount(count + 1)}> Kliknij mnie </button> </div> ); } -
useEffect: Pozwala wykonywać efekty uboczne w komponentach funkcyjnych. Podobny do metod cyklu życia komponentów klasowych (componentDidMount,componentDidUpdate,componentWillUnmount).// Przykład useEffect import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Uruchamia się po każdym renderze useEffect(() => { document.title = `Naciśnięto ${count} razy`; }); // Uruchamia się tylko przy pierwszym renderze (pusta tablica zależności) useEffect(() => { console.log('Komponent zamontowany'); return () => { console.log('Komponent odmontowany'); // Funkcja czyszczenia }; }, []); // Uruchamia się przy zmianie count useEffect(() => { console.log('Count się zmienił:', count); }, [count]); return ( <div> <p>Naciśnięto {count} razy</p> <button onClick={() => setCount(count + 1)}> Kliknij mnie </button> </div> ); } -
useContext: Pozwala subskrybować zmiany kontekstu React. Przyjmuje obiekt kontekstu utworzony za pomocąReact.createContext().// Przykład useContext import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); // Tworzenie kontekstu function ThemedButton() { const theme = useContext(ThemeContext); // Użycie kontekstu return ( <button className={theme}> Przycisk w temacie {theme} </button> ); } function App() { return ( <ThemedButton /> ); } -
useReducer: Alternatywa dlauseStatedo zarządzania bardziej złożonym stanem, obejmującym wiele podstanów lub gdy następny stan zależy od poprzedniego. Podobny do reducerów w Redux.// Przykład 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 funkcję zwrotną. Zwraca zmemoizowaną wersję callbacka, która zmienia się tylko przy zmianie jednej z zależności. Przydatne do zapobiegania niepotrzebnym ponownym renderom komponentów potomnych podczas przekazywania callbacków.// Przykład useCallback import React, { useState, useCallback } from 'react'; function Parent({ addTodo }) { const [count, setCount] = useState(0); const handleAddTodo = useCallback(() => { addTodo(); }, [addTodo]); // Zależność od addTodo return ( <> <button onClick={() => setCount(count + 1)}> Zwiększ licznik </button> <Child onAddItem={handleAddTodo} /> </> ); } function Child({ onAddItem }) { console.log('Child się renderuje'); // Będzie renderować się tylko przy zmianie onAddItem return <button onClick={onAddItem}>Dodaj element</button>; } -
useMemo: Memoizuje wartość obliczeniową. Zwraca zmemoizowaną wartość, która jest przeliczana tylko przy zmianie jednej z zależności. Przydatne dla wydajności przy kosztownych obliczeniach.// Przykład useMemo import React, { useMemo, useState } from 'react'; function expensiveCalculation(num) { console.log('Wykonywanie kosztownego obliczenia...'); 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]); // Zależność od count const addTodo = () => { setTodos(t => [...t, "Nowe zadanie"]); }; return ( <div> <div> <h2>Moje Todo</h2> {todos.map((todo, index) => ( <p key={index}>{todo}</p> ))} <button onClick={addTodo}>Dodaj Todo</button> </div> <hr /> <div> Licznik: {count} <button onClick={() => setCount(c => c + 1)}>+</button> <h2>Kosztowne obliczenie</h2> {calculation} </div> </div> ); } -
useRef: Pozwala utworzyć referencję mutowalną, która zachowuje się przez cały cykl życia komponentu. Często używana do dostępu do elementów DOM lub przechowywania dowolnej wartości mutowalnej, która nie powoduje ponownego renderowania przy zmianie.// Przykład useRef import React, { useRef } from 'react'; function TextInputWithFocusButton() { const inputEl = useRef(null); // Tworzenie ref const onButtonClick = () => { // current wskazuje na zamontowany element DOM inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> // Przypisanie ref <button onClick={onButtonClick}>Skup się na polu tekstowym</button> </> ); } -
useImperativeHandle: Konfiguruje deskryptor instancji, który jest udostępniany rodzicowi przy użyciuref. Pozwala dziecku ujawniać określone metody rodzicowi. Używane razem zforwardRef.// Przykład 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(); // Wywołanie metody z dziecka }; return ( <div> <MyInput ref={inputRef} /> <button onClick={handleFocus}>Skup się przez Parent</button> </div> ); } -
useLayoutEffect: Jest identyczny zuseEffect, ale wykonywany synchronicznie po wszystkich mutacjach DOM. Przydatny do odczytu danych z DOM lub wykonywania mutacji, które muszą zostać wykonane przed tym, jak przeglądarka odświeży ekran. Może blokować renderowanie.// Przykład useLayoutEffect import React, { useLayoutEffect, useRef } from 'react'; function Tooltip({ children, text }) { const ref = useRef(null); useLayoutEffect(() => { if (ref.current) { // Obliczenia na podstawie DOM przed odświeżeniem const { top, height } = ref.current.getBoundingClientRect(); console.log(`Element znajduje się na ${top} z wysokością ${height}`); } }, [children]); return ( <span ref={ref} title={text}> {children} </span> ); } -
useDebugValue: Wyświetla etykietę użytkownika dla hooków w React DevTools. Używany w własnych hookach do debugowania.// Przykład useDebugValue import React, { useState, useDebugValue } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); // Wyświetla 'Friend Status: Offline' lub 'Friend Status: Online' w DevTools useDebugValue(isOnline === true ? 'Online' : 'Offline'); // ... logika pobierania statusu znajomego return isOnline; } function FriendListItem({ friend }) { const isOnline = useFriendStatus(friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {friend.name} - {isOnline ? 'Online' : 'Offline'} </li> ); }
Poza wbudowanymi hookami, istnieją także własne hooki (Custom Hooks). To funkcje JavaScript, których nazwy zaczynają się od "use". Pozwalają na ponowne użycie logiki stanu między komponentami. Własny hook może wywoływać inne hooki.
// Przykład własnego hooka
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(); // Użycie własnego hooka
return (
<p>Rozmiar okna: {width}x{height}</p>
);
}
Ważne jest przestrzeganie Zasad hooków:
- Wywołuj hooki tylko na najwyższym poziomie komponentu React lub własnego hooka. Nie wywołuj ich wewnątrz pętli, warunków lub zagnieżdżonych funkcji.
- Wywołuj hooki tylko z funkcjonalnych komponentów React lub własnych hooków. Nie wywołuj ich z zwykłych funkcji JavaScript lub metod klasowych.