Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между useState и useCallback
useState и useCallback — это два важных хука React, которые служат совершенно разным целям и работают на разных уровнях управления состоянием и производительностью.
Определение
useState — это хук для управления состоянием компонента. Он позволяет функциональному компоненту иметь локальное состояние, которое будет сохраняться между рендерами.
useCallback — это хук для оптимизации производительности, который мемоизирует функцию и возвращает ее стабильную ссылку. Это предотвращает ненужные рендеры дочерних компонентов.
Основные различия
1. Назначение
useState управляет данными компонента:
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// Состояние изменяется, компонент перерендеривается
setCount(count + 1);
useCallback управляет функциями и их стабильностью:
const handleClick = useCallback(() => {
console.log('Clicked');
}, []); // Функция мемоизируется
2. Когда срабатывает
useState срабатывает при каждом вызове setter функции:
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1); // Вызов setter -> перерендер
};
return <button onClick={increment}>{count}</button>;
}
useCallback срабатывает при изменении зависимостей:
function Parent() {
const [count, setCount] = useState(0);
// handleClick пересоздается только если count изменяется
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
return <Child onClick={handleClick} />;
}
Практические примеры
Пример 1: useState для управления состоянием
import { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
setTodos([...todos, { id: Date.now(), text: input }]);
setInput(''); // Очистить input
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(todo => <li key={todo.id}>{todo.text}</li>)}
</ul>
</div>
);
}
Пример 2: useCallback для оптимизации
import { useState, useCallback } from 'react';
// Дочерний компонент, оптимизированный через React.memo
const Child = React.memo(({ onClick }) => {
console.log('Child rendered');
return <button onClick={onClick}>Click me</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// БЕЗ useCallback - Child перерендеривается при каждом изменении name
// const handleClick = () => setCount(count + 1);
// С useCallback - Child не перерендеривается, если count не меняется
const handleClick = useCallback(() => {
setCount(prev => prev + 1);
}, []);
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
<p>Count: {count}</p>
<Child onClick={handleClick} />
</div>
);
}
Пример 3: useState + useCallback вместе
import { useState, useCallback } from 'react';
function SearchUsers() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
// useCallback оборачивает функцию, которая обновляет состояние
const handleSearch = useCallback(async (searchTerm) => {
if (!searchTerm) {
setResults([]);
return;
}
setLoading(true);
try {
const data = await fetch(`/api/search?q=${searchTerm}`);
const users = await data.json();
setResults(users);
} finally {
setLoading(false);
}
}, []); // Зависимостей нет, функция стабильна
return (
<div>
<input
value={query}
onChange={(e) => {
setQuery(e.target.value);
handleSearch(e.target.value);
}}
/>
{loading && <p>Loading...</p>}
<ul>
{results.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
</div>
);
}
Когда использовать
useState используется когда:
- Нужно хранить и обновлять данные компонента
- Изменение данных должно вызывать перерендер
- Нужна реактивность на пользовательский ввод
useCallback используется когда:
- Передаешь функцию в оптимизированные дочерние компоненты (React.memo)
- Функция является зависимостью других хуков (useEffect, useMemo)
- Хочешь избежать ненужных рендеров
Важные замечания
// useCallback не должен заменять useState
const [count, setCount] = useState(0);
// Неправильно - это не заменит useState
const handleIncrement = useCallback(() => {
setCount(count + 1);
}, [count]);
// useCallback здесь просто стабилизирует функцию,
// не более того
Вывод
useState отвечает за данные и реактивность компонента. useCallback отвечает за производительность и стабильность ссылок на функции. Это совершенно разные инструменты для разных задач. Используй useState для управления состоянием, а useCallback для оптимизации производительности при передаче функций в дочерние компоненты.