Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Есть ли в React аналоги useEffect
useEffect — это хук для управления побочными эффектами (side effects) в функциональных компонентах. В React есть несколько хуков, которые служат похожим или дополняющим целям.
useEffect и его назначение
Первый, давай разберёмся, для чего нужен useEffect:
import { useEffect, useState } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// useEffect срабатывает ПОСЛЕ рендера
useEffect(() => {
const fetchUser = async () => {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
setLoading(false);
};
fetchUser();
}, [userId]); // dependency array
return loading ? <div>Loading...</div> : <div>{user.name}</div>;
}
useEffect используется для:
- Загрузки данных с сервера
- Подписки на события
- Таймеры и интервалы
- Работа с DOM
- Очистка ресурсов
Аналоги и альтернативы useEffect
1. useLayoutEffect — синхронный useEffect
import { useLayoutEffect } from "react";
function MeasureComponent() {
const [height, setHeight] = useState(0);
const divRef = useRef(null);
// useLayoutEffect срабатывает ПЕРЕД отрисовкой браузером
// (после render, но ДО paint)
useLayoutEffect(() => {
if (divRef.current) {
setHeight(divRef.current.offsetHeight);
}
}, []);
return (
<div>
<div ref={divRef}>Контент</div>
<p>Высота: {height}px</p>
</div>
);
}
// Сравнение:
// useEffect: render -> paint -> effect
// useLayoutEffect: render -> effect -> paint
Когда использовать useLayoutEffect:
- Измерение размеров DOM элементов
- Синхронное изменение DOM (избежать мигания)
- Фокусировка на элемент сразу же
2. useCallback — мемоизация функций
import { useCallback } from "react";
function SearchComponent() {
const [query, setQuery] = useState("");
// useCallback создает мемоизированную функцию
// которая не создается заново при каждом рендере
const handleSearch = useCallback((q) => {
fetch(`/api/search?q=${q}`);
}, []); // зависимости
return (
<input
onChange={(e) => handleSearch(e.target.value)}
placeholder="Поиск..."
/>
);
}
// Разница:
// БЕЗ useCallback:
function Component() {
const handleClick = () => console.log("clicked"); // НОВАЯ функция каждый рендер
return <Child onClick={handleClick} />;
}
// С useCallback:
function Component() {
const handleClick = useCallback(
() => console.log("clicked"),
[]
); // ОДНА и та же функция
return <Child onClick={handleClick} />;
}
3. useMemo — мемоизация вычислений
import { useMemo } from "react";
function HeavyComponent({ items, filter }) {
// useMemo кэширует результат вычисления
// вычисление запускается только если dependencies изменились
const filteredItems = useMemo(() => {
console.log("Фильтрую...");
return items.filter((item) => item.category === filter);
}, [items, filter]);
return (
<ul>
{filteredItems.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
// Сравнение:
// БЕЗ useMemo: каждый рендер фильтрует заново (медленно)
// С useMemo: кэширует результат, вычисляет только при изменении зависимостей
4. useRef — доступ к DOM и сохранение значений
import { useRef } from "react";
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Сфокусировать</button>
</>
);
}
// useRef также может сохранять значения между рендерами
function Timer() {
const intervalRef = useRef(null);
const [count, setCount] = useState(0);
const startTimer = () => {
// Сохраняем ID интервала в ref
intervalRef.current = setInterval(() => {
setCount((c) => c + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(intervalRef.current);
};
return (
<>
<p>{count}</p>
<button onClick={startTimer}>Старт</button>
<button onClick={stopTimer}>Стоп</button>
</>
);
}
5. useContext — доступ к контексту
import { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function ThemedComponent() {
// useContext получает значение из контекста
const theme = useContext(ThemeContext);
return <div className={theme}>Контент</div>;
}
// useContext заменяет useEffect для подписки на контекст
// Когда контекст изменяется, компонент ререндеривается
6. useReducer — управление сложным состоянием
import { useReducer } from "react";
const initialState = { count: 0, error: null };
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
case "ERROR":
return { ...state, error: action.payload };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: "INCREMENT" })}>
+
</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>
-
</button>
</>
);
}
// useReducer + useEffect часто используются вместе
useEffect(() => {
fetchData().catch((error) => {
dispatch({ type: "ERROR", payload: error });
});
}, []);
Новое в React 19: useTransition и useDeferred
import { useTransition } from "react";
function SearchResults({ query }) {
const [isPending, startTransition] = useTransition();
const [results, setResults] = useState([]);
const handleSearch = (q) => {
// startTransition говорит React: это обновление может быть slow
startTransition(() => {
fetchResults(q).then(setResults);
});
};
return (
<>
{isPending && <div>Загрузка...</div>}
<ResultList results={results} />
</>
);
}
// useTransition заменяет некоторые use cases useEffect
// для управления асинхронными операциями
Сравнительная таблица
| Хук | Назначение | Когда использовать |
|---|---|---|
| useEffect | Side effects (загрузка данных, подписки) | Асинхронные операции, таймеры, слушатели |
| useLayoutEffect | Синхронные эффекты, измерения DOM | Фокусировка, измерение, синхронный DOM |
| useCallback | Мемоизация функций | Передача коллбэков в оптимизированные компоненты |
| useMemo | Кэширование вычислений | Тяжелые вычисления, фильтрация массивов |
| useRef | Доступ к DOM, сохранение значений | Прямой доступ к элементам, таймеры |
| useContext | Доступ к контексту | Глобальное состояние (тема, авторизация) |
| useReducer | Управление сложным состоянием | Логика с множеством переходов состояний |
| useTransition | Управление приоритетом обновлений | Асинхронные обновления UI |
Практический пример: загрузка данных
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// useEffect для загрузки
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then((r) => r.json())
.then((data) => setUser(data))
.catch((err) => setError(err))
.finally(() => setLoading(false));
}, [userId]);
if (loading) return <div>Загрузка...</div>;
if (error) return <div>Ошибка: {error.message}</div>;
return <div>{user.name}</div>;
}
Итог
useEffect — это основной хук для side effects. Но React предоставляет много других хуков для разных целей:
- useLayoutEffect — когда нужно синхронное выполнение
- useCallback/useMemo — для оптимизации производительности
- useRef — для доступа к DOM
- useContext/useReducer — для управления состоянием
- useTransition — для приоритизации обновлений
Каждый хук имеет свою роль, и часто они используются вместе.