Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между React Context и useContext
Основное уточнение
Eslo это не совсем правильная пара для сравнения. React Context — это API, а useContext — это хук для использования Context. Это как сравнивать "что такое электричество" и "как включить лампу". Но вопрос часто подразумевает путаницу, поэтому разберём всё подробно.
React Context API
Создание Context
import { createContext } from 'react';
// React.Context создаётся один раз
const ThemeContext = createContext();
// Это просто объект с методами Provider и Consumer
console.log(ThemeContext);
// {
// $$typeof: Symbol(react.context)
// Provider: {...}
// Consumer: {...}
// }
Context — это объект, содержащий информацию о том, как передавать данные вниз по дереву компонентов.
Provider и Consumer
// Provider - оборачивает компоненты
<ThemeContext.Provider value={{ dark: true }}>
<Header />
<Main />
<Footer />
</ThemeContext.Provider>
// Consumer - класс-компонент способ доступа (старый)
<ThemeContext.Consumer>
{value => <div>{value.dark ? 'Dark' : 'Light'}</div>}
</ThemeContext.Consumer>
useContext Hook
Что это такое
// useContext - это хук для доступа к значению Context
const theme = useContext(ThemeContext);
// Это "синтаксический сахар" вместо Consumer
// Вместо:
<ThemeContext.Consumer>
{value => /* используй value */}
</ThemeContext.Consumer>
// Пишешь:
const value = useContext(ThemeContext);
// Используй value
useContext — это хук, который позволяет получить значение из Context внутри компонента.
Детальное сравнение
До useContext (класс-компоненты)
// Context создаётся один раз
const AuthContext = createContext(null);
// Provider
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}>
{children}
</AuthContext.Provider>
);
}
// Consumer (класс-компонент)
class UserProfile extends React.Component {
static contextType = AuthContext; // Единственный Context может быть
render() {
const { user } = this.context;
return <div>{user?.name}</div>;
}
}
// Или функциональный компонент с Consumer
function UserCard() {
return (
<AuthContext.Consumer>
{({ user }) => <div>{user?.name}</div>}
</AuthContext.Consumer>
);
}
С useContext (современный подход)
// Context создаётся один раз (такой же)
const AuthContext = createContext(null);
// Provider (такой же)
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}>
{children}
</AuthContext.Provider>
);
}
// Компонент с useContext (намного проще!)
function UserProfile() {
const { user } = useContext(AuthContext);
return <div>{user?.name}</div>;
}
function UserCard() {
const { user } = useContext(AuthContext);
return <div>{user?.name}</div>;
}
Практический пример: Theme Context
// 1. Создание Context (один раз)
const ThemeContext = createContext();
// 2. Provider компонент
function ThemeProvider({ children }) {
const [isDark, setIsDark] = useState(false);
const toggleTheme = () => {
setIsDark(prev => !prev);
};
return (
<ThemeContext.Provider value={{ isDark, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// 3. Кастомный хук для удобства
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme должен быть внутри ThemeProvider');
}
return context;
}
// 4. Использование в компонентах
function Header() {
const { isDark, toggleTheme } = useTheme();
return (
<header style={{ background: isDark ? '#000' : '#fff' }}>
<button onClick={toggleTheme}>
{isDark ? 'Light' : 'Dark'}
</button>
</header>
);
}
// 5. Обёртка приложения
function App() {
return (
<ThemeProvider>
<Header />
<Main />
<Footer />
</ThemeProvider>
);
}
Сравнение в таблице
| Аспект | React Context | useContext |
|---|---|---|
| Тип | API, объект | Хук |
| Когда создаётся | Один раз | - |
| Где используется | Provider/Consumer | Внутри функциональных компонентов |
| Синтаксис | <Context.Provider> | const value = useContext(Context) |
| Совместимость | Всё (классы и функции) | Только функциональные компоненты |
| Сложность | Многословно | Просто |
| Производительность | Одинаковая | Одинаковая |
Важные моменты
1. Context сам по себе не вызывает перендер
const UserContext = createContext();
function App() {
const [count, setCount] = useState(0);
// При каждом рендере создаётся новый объект!
// Это вызовет ненужные перендеры всех потребителей
const value = { count, setCount }; // ПЛОХО!
return (
<UserContext.Provider value={value}>
<Child />
</UserContext.Provider>
);
}
2. Оптимизация Context
function App() {
const [count, setCount] = useState(0);
// Мемоизируй значение
const value = useMemo(() => ({ count, setCount }), [count]);
return (
<UserContext.Provider value={value}>
<Child />
</UserContext.Provider>
);
}
3. Multiple Contexts
// useContext работает с одним Context
const theme = useContext(ThemeContext);
const auth = useContext(AuthContext);
const settings = useContext(SettingsContext);
// Несколько Provider'ов
function App() {
return (
<AuthProvider>
<ThemeProvider>
<SettingsProvider>
<Main />
</SettingsProvider>
</ThemeProvider>
</AuthProvider>
);
}
Когда использовать
Context хорош для:
- Глобального состояния (тема, язык, профиль пользователя)
- Избегания prop drilling
- Конфигурации приложения
Context НЕ подходит для:
- Часто меняющихся данных (вызывает лишние перендеры)
- Сложного состояния (используй Redux, Zustand)
- Больших объёмов данных
Заключение
React Context API — это механизм для передачи данных вниз по дереву компонентов. useContext — это хук, который позволяет получить значение из Context в функциональных компонентах.
Это не альтернативы друг другу, а части одного целого. Context API без useContext возможен (через Consumer), но useContext без Context невозможен — он всегда работает с Context объектом.