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

Что такое состояние в React?

1.6 Junior🔥 241 комментариев
#React#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Состояние (State) в React

Состояние в React — это объект, который содержит данные, специфичные для компонента. Когда состояние изменяется, компонент перерендеривается с новыми значениями. Состояние позволяет компонентам быть интерактивными и реагировать на действия пользователя.

Основные характеристики состояния

  1. Локальность: состояние принадлежит компоненту и недоступно другим компонентам
  2. Реактивность: при изменении состояния компонент автоматически перерендеривается
  3. Изменяемость: состояние нужно обновлять через специальные функции, а не прямым присваиванием
  4. Асинхронность: обновления состояния могут быть батчированы (объединены)

useState Hook

Современный способ работы с состоянием в функциональных компонентах:

import { useState } from "react";

function Counter() {
  // useState возвращает текущее значение и функцию для обновления
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Счетчик: {count}</p>
      <button onClick={() => setCount(count + 1)}>Увеличить</button>
    </div>
  );
}

Как это работает:

  • count — текущее значение состояния (начальное значение 0)
  • setCount — функция для обновления состояния
  • При клике на кнопку setCount(count + 1) обновляет состояние
  • React обнаруживает изменение и перерендеривает компонент

Типичные примеры

Пример 1: Форма с полями ввода

function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState(null);
  
  const handleSubmit = (e) => {
    e.preventDefault();
    
    if (!email.includes("@")) {
      setError("Некорректный email");
      return;
    }
    
    setError(null);
    console.log("Отправляем:", { email, password });
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Пароль"
      />
      {error && <p style={{ color: "red" }}>{error}</p>}
      <button type="submit">Вход</button>
    </form>
  );
}

Пример 2: Список с добавлением элементов

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: "Купить молоко", done: false },
    { id: 2, text: "Написать код", done: true },
  ]);
  const [input, setInput] = useState("");
  
  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, {
        id: Date.now(),
        text: input,
        done: false,
      }]);
      setInput("");
    }
  };
  
  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    ));
  };
  
  const deleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };
  
  return (
    <div>
      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="Новая задача"
      />
      <button onClick={addTodo}>Добавить</button>
      
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.done}
              onChange={() => toggleTodo(todo.id)}
            />
            <span style={{
              textDecoration: todo.done ? "line-through" : "none"
            }}>
              {todo.text}
            </span>
            <button onClick={() => deleteTodo(todo.id)}>Удалить</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Важные правила работы с состоянием

Правило 1: Не изменяйте состояние напрямую

// ❌ Неправильно — React не заметит изменения
const [count, setCount] = useState(0);
count++; // Так нельзя!

// ✅ Правильно — используйте setCount
setCount(count + 1);

Правило 2: Обновляйте объекты и массивы копированием

// ❌ Неправильно — изменение исходного объекта
const [user, setUser] = useState({ name: "Alice", age: 30 });
user.age = 31; // Так нельзя!

// ✅ Правильно — создаем новый объект
setUser({ ...user, age: 31 });
setUser(prev => ({ ...prev, age: prev.age + 1 }));

// ❌ Неправильно для массивов
const [items, setItems] = useState([1, 2, 3]);
items.push(4); // Так нельзя!

// ✅ Правильно для массивов
setItems([...items, 4]);
setItems(prev => [...prev, 4]);

Правило 3: Используйте функцию обновления для зависимостей

const [count, setCount] = useState(0);

// Если обновление зависит от предыдущего значения:
setCount(prevCount => prevCount + 1);

// Это важно в асинхронных операциях:
setTimeout(() => {
  setCount(prev => prev + 1); // prev = текущее значение
}, 1000);

Состояние vs Props

АспектStateProps
ИсточникВнутри компонентаОт родителя
ИзменениеКомпонент может менятьТолько для чтения
Когда использоватьДанные, которые меняютсяКонфигурация, параметры
ПеререндерингКомпонент перерендериваетсяРодитель перерендеривается
// State — меняется сам компонент
const [isOpen, setIsOpen] = useState(false);

// Props — приходят от родителя
function Modal({ isOpen, onClose, title }) {
  // isOpen и title — props (для чтения)
  // onClose — callback от родителя
}

Проблема и решение: Стейт лифтинг

// Если два компонента должны синхронизировать состояние,
// поднимите его в родительский компонент

// ❌ Неправильно — состояние в разных компонентах
function Input1() {
  const [value, setValue] = useState("");
}

function Input2() {
  const [value, setValue] = useState(""); // Разные значения!
}

// ✅ Правильно — состояние в родителе
function Parent() {
  const [value, setValue] = useState("");
  
  return (
    <>
      <Input1 value={value} onChange={setValue} />
      <Input2 value={value} onChange={setValue} />
    </>
  );
}

Сложное состояние

Для сложных случаев используйте useReducer:

const initialState = { count: 0, step: 1 };

function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return { ...state, count: state.count + state.step };
    case "DECREMENT":
      return { ...state, count: state.count - state.step };
    case "SET_STEP":
      return { ...state, step: action.payload };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  
  return (
    <div>
      <p>Счетчик: {state.count}</p>
      <p>Шаг: {state.step}</p>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>+</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>-</button>
      <input
        value={state.step}
        onChange={(e) => dispatch({
          type: "SET_STEP",
          payload: parseInt(e.target.value)
        })}
      />
    </div>
  );
}

Лучшие практики

  1. Держите состояние как можно ближе к месту использования
  2. Используйте функции обновления для зависимостей от предыдущего состояния
  3. Не создавайте новые объекты в функции render
  4. Используйте правильные имена переменных состояния
  5. Рассмотрите Context API для глобального состояния
  6. Используйте Zustand или Redux для сложного глобального состояния

Состояние — это один из ключевых механизмов React, который делает компоненты интерактивными и реактивными на изменения данных.

Что такое состояние в React? | PrepBro