← Назад к вопросам

В каком state будешь хранить данные

2.0 Middle🔥 211 комментариев
#State Management

Комментарии (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>
  );
}

Рекомендация по выбору

Тип данныхГде хранитьПример
Локальный UIuseStateоткрыто ли меню, значение инпута
Несколько компонентов-сестёрподнять в родителявыбранный товар в корзине
Глобальное (юзер, тема)Context или Reduxавторизованный пользователь
Данные с сервераuseState + useEffectсписок постов из БД
Фильтры, поиск, пагинацияURL/products?category=electronics&page=2
Сохранение между сеансамиlocalStorageизбранные товары, тема

Ключевые принципы

  • Начни просто — с useState в самом маленьком компоненте
  • Подними выше — если нужно нескольким компонентам
  • Context или Redux — для действительно глобального состояния
  • URL — для фильтров, чтобы ссылка была шерируемой
  • Не смешивай состояние сервера и UI в одно место