Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В каком state будешь хранить данные
Выбор места для хранения состояния зависит от масштаба и области использования данных. Существуют несколько уровней управления состоянием в React, и каждый имеет своё назначение.
1. Локальное состояние компонента (useState)
Храни в useState, если данные:
- используются только в этом компоненте
- не нужны другим компонентам
- специфичны для UI (открыто ли меню, значение инпута и т.д.)
import { useState } from "react";
function SearchInput() {
// Состояние инпута живет только в этом компоненте
const [query, setQuery] = useState("");
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<input value={query} onChange={e => setQuery(e.target.value)} />
{isOpen && <ul>{/* результаты поиска */}</ul>}
</div>
);
}
2. Поднятие состояния (Lifting State Up)
Если данные нужны нескольким компонентам-сёстрам, подними состояние в общего родителя:
function ParentComponent() {
const [selectedUser, setSelectedUser] = useState(null);
return (
<div>
{/* Передаём состояние в дочерние компоненты */}
<UserList onSelect={setSelectedUser} />
<UserProfile user={selectedUser} />
</div>
);
}
3. Context API для глобального состояния
Для данных, нужных во всём приложении или его части, используй React Context:
import { createContext, useContext, useState } from "react";
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const login = async (email, password) => {
const response = await fetch("/api/login", {
method: "POST",
body: JSON.stringify({ email, password })
});
const data = await response.json();
setUser(data);
setIsAuthenticated(true);
};
return (
<AuthContext.Provider value={{ user, isAuthenticated, login }}>
{children}
</AuthContext.Provider>
);
}
// Использование
function MyComponent() {
const { user, isAuthenticated } = useContext(AuthContext);
return <p>{isAuthenticated ? user.name : "Гость"}</p>;
}
4. Состояние сервера vs состояние клиента
Состояние сервера (данные из БД) отличается от состояния UI:
function UserProfile({ userId }) {
// Состояние СЕРВЕРА — данные пользователя из БД
const [userData, setUserData] = useState(null);
// Состояние UI — локальное управление интерфейсом
const [isEditing, setIsEditing] = useState(false);
const [editFormData, setEditFormData] = useState("");
useEffect(() => {
// Загружаем данные с сервера
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setUserData);
}, [userId]);
return (
<div>
{!isEditing && <p>{userData?.name}</p>}
{isEditing && (
<input
value={editFormData}
onChange={e => setEditFormData(e.target.value)}
/>
)}
<button onClick={() => setIsEditing(!isEditing)}>
{isEditing ? "Сохранить" : "Редактировать"}
</button>
</div>
);
}
5. Библиотеки управления состоянием (Redux, Zustand)
Для сложных приложений с большим и часто изменяющимся состоянием:
// С Zustand
import { create } from "zustand";
const useStore = create(set => ({
users: [],
selectedUser: null,
fetchUsers: async () => {
const response = await fetch("/api/users");
const users = await response.json();
set({ users });
},
selectUser: (user) => set({ selectedUser: user })
}));
function App() {
const { users, selectedUser, fetchUsers } = useStore();
useEffect(() => {
fetchUsers();
}, []);
return <div>{selectedUser?.name}</div>;
}
6. URL State (для фильтров и пагинации)
При изменении фильтров и пагинации, сохраняй в URL, чтобы ссылка была шерируемой:
import { useSearchParams } from "next/navigation";
function PostsList() {
const [searchParams, setSearchParams] = useSearchParams();
const page = searchParams.get("page") || "1";
const category = searchParams.get("category") || "all";
const handlePageChange = (newPage) => {
setSearchParams({ page: newPage, category });
};
return (
<div>
<Pagination page={page} onChange={handlePageChange} />
<CategoryFilter current={category} onChange={cat =>
setSearchParams({ page: "1", category: cat })
} />
</div>
);
}
7. LocalStorage для сохранения между сеансами
Для данных, которые должны сохраняться после закрытия страницы:
import { useEffect, useState } from "react";
function usePersistentState(key, initialValue) {
const [state, setState] = useState(() => {
// Загружаем из localStorage
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initialValue;
});
// Сохраняем в localStorage при изменении
useEffect(() => {
localStorage.setItem(key, JSON.stringify(state));
}, [state, key]);
return [state, setState];
}
// Использование
function App() {
const [theme, setTheme] = usePersistentState("theme", "light");
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Переключить на {theme === "light" ? "тёмную" : "светлую"} тему
</button>
);
}
Рекомендация по выбору
| Тип данных | Где хранить | Пример |
|---|---|---|
| Локальный UI | useState | открыто ли меню, значение инпута |
| Несколько компонентов-сестёр | поднять в родителя | выбранный товар в корзине |
| Глобальное (юзер, тема) | Context или Redux | авторизованный пользователь |
| Данные с сервера | useState + useEffect | список постов из БД |
| Фильтры, поиск, пагинация | URL | /products?category=electronics&page=2 |
| Сохранение между сеансами | localStorage | избранные товары, тема |
Ключевые принципы
- Начни просто — с useState в самом маленьком компоненте
- Подними выше — если нужно нескольким компонентам
- Context или Redux — для действительно глобального состояния
- URL — для фильтров, чтобы ссылка была шерируемой
- Не смешивай состояние сервера и UI в одно место