Какие существуют хуки в React?
Ответ от нейросети
sobes.tech AI
В React, начиная с версии 16.8, хуки предоставляют функциональным компонентам возможность управлять состоянием и использовать жизненные циклы, которые ранее были доступны только классовым компонентам.
Вот основные встроенные хуки:
-
useState: Позволяет добавить внутреннее состояние к функциональному компоненту. Возвращает пару: текущее состояние и функцию для его обновления.// Пример useState import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); // Инициализация состояния с 0 return ( <div> <p>Вы нажали {count} раз</p> <button onClick={() => setCount(count + 1)}> Нажми меня </button> </div> ); } -
useEffect: Позволяет выполнять побочные эффекты в функциональных компонентах. Схож с методами жизненного цикла классовых компонентов (componentDidMount,componentDidUpdate,componentWillUnmount).// Пример useEffect import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Срабатывает после каждого рендера useEffect(() => { document.title = `Вы нажали ${count} раз`; }); // Срабатывает только при первом рендере (пустой массив зависимостей) useEffect(() => { console.log('Компонент смонтирован'); return () => { console.log('Компонент размонтирован'); // Функция очистки }; }, []); // Срабатывает при изменении count useEffect(() => { console.log('Count изменился:', count); }, [count]); return ( <div> <p>Вы нажали {count} раз</p> <button onClick={() => setCount(count + 1)}> Нажми меня </button> </div> ); } -
useContext: Позволяет подписаться на изменения контекста React. Принимает объект контекста, созданный с помощьюReact.createContext().// Пример useContext import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); // Создание контекста function ThemedButton() { const theme = useContext(ThemeContext); // Использование контекста return ( <button className={theme}> Кнопка в теме {theme} </button> ); } function App() { return ( <ThemedButton /> ); } -
useReducer: АльтернативаuseStateдля управления более сложным состоянием, которое включает несколько подзначений или когда следующее состояние зависит от предыдущего. Похож на редюсеры в Redux.// Пример 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: Мемоизирует функцию-обратного вызова. Возвращает мемоизированную версию колбэка, которая изменяется только при изменении одной из зависимостей. Полезно для предотвращения ненужных перерисовок дочерних компонентов при передаче колбэков.// Пример useCallback import React, { useState, useCallback } from 'react'; function Parent({ addTodo }) { const [count, setCount] = useState(0); const handleAddTodo = useCallback(() => { addTodo(); }, [addTodo]); // Зависимость от addTodo return ( <> <button onClick={() => setCount(count + 1)}> Увеличить счет </button> <Child onAddItem={handleAddTodo} /> </> ); } function Child({ onAddItem }) { console.log('Child рендерится'); // Будет рендериться только при изменении onAddItem return <button onClick={onAddItem}>Добавить элемент</button>; } -
useMemo: Мемоизирует вычисляемое значение. Возвращает мемоизированное значение, которое пересчитывается только при изменении одной из зависимостей. Полезно для производительности при дорогих вычислениях.// Пример useMemo import React, { useMemo, useState } from 'react'; function expensiveCalculation(num) { console.log('Выполняется дорогое вычисление...'); 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]); // Зависимость от count const addTodo = () => { setTodos(t => [...t, "New Todo"]); }; return ( <div> <div> <h2>Мои Todo</h2> {todos.map((todo, index) => ( <p key изветстверных={index}>{todo}</p> ))} <button onClick={addTodo}>Добавить Todo</button> </div> <hr /> <div> Счет: {count} <button onClick={() => setCount(c => c + 1)}>+</button> <h2>Дорогое вычисление</h2> {calculation} </div> </div> ); } -
useRef: Позволяет создать мутабельный ref, который сохраняется в течение всего жизненного цикла компонента. Часто используется для доступа к элементам DOM или хранения любого мутабельного значения, которое не вызывает перерисовок при изменении.// Пример useRef import React, { useRef, useEffect } from 'react'; function TextInputWithFocusButton() { const inputEl = useRef(null); // Создание ref const onButtonClick = () => { // current указывает на смонтированный элемент DOM inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> // Привязка ref <button onClick={onButtonClick}>Фокус на поле ввода</button> </> ); } -
useImperativeHandle: Настраивает дескриптор экземпляра, который предоставляется родительскому компоненту при использованииref. Позволяет дочернему компоненту раскрывать определенные методы родительскому компоненту. Используется совместно сforwardRef.// Пример 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(); // Вызов метода из дочернего компонента }; return ( <div> <MyInput ref={inputRef} /> <button onClick={handleFocus}>Фокус через Parent</button> </div> ); } -
useLayoutEffect: ИдентиченuseEffect, но выполняется синхронно после всех мутаций DOM. Полезен для чтения данных из DOM или выполнения мутаций, которые необходимо сделать до того, как браузер перерисует экран. Может блокировать рендеринг.// Пример useLayoutEffect import React, { useLayoutEffect, useRef } from 'react'; function Tooltip({ children, text }) { const ref = useRef(null); useLayoutEffect(() => { if (ref.current) { // Вычисления на основе DOM перед перерисовкой const { top, height } = ref.current.getBoundingClientRect(); console.log(`Элемент находится на ${top} с высотой ${height}`); } }, [children]); return ( <span ref={ref} title={text}> {children} </span> ); } -
useDebugValue: Отображает пользовательскую метку для хуков в React DevTools. Используется в пользовательских хуках для отладки.// Пример useDebugValue import React, { useState, useDebugValue } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); // Отображает 'Friend Status: Offline' или 'Friend Status: Online' в DevTools useDebugValue(isOnline === true ? 'Online' : 'Offline'); // ... логика получения статуса друга return isOnline; } function FriendListItem({ friend }) { const isOnline = useFriendStatus(friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {friend.name} - {isOnline ? 'Online' : 'Offline'} </li> ); }
Помимо встроенных хуков, существуют также пользовательские хуки (Custom Hooks). Это JavaScript-функции, имена которых начинаются с "use". Они позволяют повторно использовать логику состояния между компонентами. Пользовательский хук может вызывать другие хуки.
// Пример пользовательского хука
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(); // Использование пользовательского хука
return (
<p>Размер окна: {width}x{height}</p>
);
}
Важно соблюдать Правила хуков:
- Вызывайте хуки только на верхнем уровне компонента React или пользовательского хука. Не вызывайте их внутри циклов, условий или вложенных функций.
- Вызывайте хуки только из функциональных компонентов React или пользовательских хуков. Не вызывайте их из обычных JavaScript-функций или методов классовых компонентов.