Хотите заказать веб-сайт? Связаться с нами

Props и State — как React управляет данными

Цель урока: понять два главных механизма работы с данными в React: Props (данные передаются сверху вниз, readonly) и State (данные живут внутри компонента, изменяемы). Научиться передавать данные между компонентами и управлять динамическим интерфейсом.

Props и State — как React управляет данными

Введение: данные в React

Любое React-приложение — это поток данных. Данные должны откуда-то приходить, где-то храниться и как-то обновлять интерфейс.

Два главных инструмента для данных:

Концепция Что это Можно изменять? Откуда берётся?
Props Параметры компонента ❌ Нет (readonly) Передаются от родителя
State Внутреннее состояние ✅ Да (через setState) Живёт внутри компонента

Главная мысль:

  1. Props— это входные данные компонента (как аргументы функции).
  2. State — это внутренняя память компонента (как переменные внутри функции).

Props — свойства компонента

Props (сокращение от «properties») — это данные, которые родительский компонент передаёт дочернему.

Передача props:

function App() {
  return (
    <UserCard 
      name="Алексей" 
      age={25} 
      city="Москва" 
      isActive={true}
    />
  );
}

Получение props в компоненте:

function UserCard(props) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>Возраст: {props.age}</p>
      <p>Город: {props.city}</p>
      <p>Статус: {props.isActive ? 'Активен' : 'Не активен'}</p>
    </div>
  );
}

Деструктуризация props (лучший способ):

function UserCard({ name, age, city, isActive }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>Возраст: {age}</p>
      <p>Город: {city}</p>
      <p>Статус: {isActive ? 'Активен' : 'Не активен'}</p>
    </div>
  );
}

Props — только для чтения

Важнейшее правило React

Props нельзя изменять внутри компонента.

❌ Неправильно (ошибка):

function UserCard({ name }) {
  name = "Иван"; // ОШИБКА! Нельзя менять props
  return <h2>{name}</h2>;
}

✅ Правильно (props только читаем):

function UserCard({ name }) {
  const displayName = name.toUpperCase(); // Можно использовать, но не менять
  return <h2>{displayName}</h2>;
}

Почему так?

  1. Props — это аргументы функции
  2. Функция не должна менять свои аргументы (чистота функций)
  3. React должен предсказуемо работать

Значения по умолчанию для props

Можно задать значения по умолчанию, если prop не передан:

Способ 1. Через defaultProps (классовый стиль):

function UserCard({ name, age, city }) {
  return <div>{name}, {age}, {city}</div>;
}

UserCard.defaultProps = {
  name: 'Гость',
  age: 0,
  city: 'Неизвестно'
};

Способ 2. Через деструктуризацию (рекомендуется):

function UserCard({ name = 'Гость', age = 0, city = 'Неизвестно' }) {
  return <div>{name}, {age}, {city}</div>;
}
Из ноутбука появляются летающие светящиеся экраны

Оживи свой сайт. Освой JavaScript!

Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.

От теории — к реальным скриптам в твоём портфолио.

Подробнее о курсе

State — внутреннее состояние компонента

State — это данные, которые компонент хранит сам в себе и может изменять. Когда state меняется, компонент перерисовывается.

Как работает state

  1. Ты объявляешь state с начальным значением
  2. React запоминает это значение
  3. Когда ты вызываешь функцию обновления, React изменяет значение и перерисовывает компонент
  4. Компонент видит новое значение state

Хук useState — главный инструмент для state

Синтаксис:

const [state, setState] = useState(initialValue);

Разбор:

  1. state — текущее значение (например, count)
  2. setState — функция для обновления (например, setCount)
  3. initialValue — начальное значение (например, 0)

Простейший пример (счётчик):

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // начальное значение 0

  const increment = () => {
    setCount(count + 1); // увеличиваем на 1
  };

  return (
    <div>      
      <button onClick={increment}>Счёт: {count}</button>
    </div>
  );
}

На экране: При клике на кнопку число увеличивается на 1.

Пример реализации показан ниже.

Обновление state (два способа)

Способ 1. Прямое обновление (если новое значение не зависит от старого):

setCount(5); // всегда устанавливаем 5
setName('Иван'); // всегда устанавливаем 'Иван'

Способ 2. Обновление через функцию (если зависит от старого значения):

setCount(prevCount => prevCount + 1); // безопасно для асинхронности
setCount(prevCount => prevCount * 2);

Когда использовать второй способ?

  1. Когда новое значение зависит от старого
  2. Когда обновление может быть асинхронным (много вызовов подряд)
  3. Всегда, если есть сомнения

Пример с асинхронностью:

// ❌ Может не сработать правильно
setCount(count + 1);
setCount(count + 1); // Может прибавить только 1, а не 2

// ✅ Всегда сработает правильно
setCount(prev => prev + 1);
setCount(prev => prev + 1); // Прибавит 2

Состояния разных типов

Строка:

const [name, setName] = useState('Алексей');

Число:

const [age, setAge] = useState(25);

Булево (true/false):

const [isActive, setIsActive] = useState(true);

Массив:

const [items, setItems] = useState(['Яблоко', 'Банан']);

Объект:

const [user, setUser] = useState({ name: 'Алексей', age: 25 });

Обновление объектов и массивов в state

Важно: State нельзя менять напрямую! Нужно создавать новый объект/массив.

❌ Неправильно:

user.name = 'Иван'; // ОШИБКА! Мутация объекта
setUser(user);

✅ Правильно (объект):

setUser({ ...user, name: 'Иван' }); // Создаём новый объект

✅ Правильно (массив):

setItems([...items, 'Апельсин']); // Добавляем в конец
setItems(items.filter(item => item !== 'Банан')); // Удаляем

Подъём состояния (Lifting State Up)

Если несколько компонентов используют одни и те же данные, state нужно «поднять» к их общему родителю.

Проблема: Два компонента не могут иметь общий state напрямую.

Решение: state живёт в родителе, а дочерние компоненты получают его через props.

Пример:

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

  return (
    <div>
      <ChildA count={count} />
      <ChildB setCount={setCount} />
    </div>
  );
}

function ChildA({ count }) {
  return <p>Счёт: {count}</p>;
}

function ChildB({ setCount }) {
  return <button onClick={() => setCount(prev => prev + 1)}>+1</button>;
}

Важно: Теперь оба компонента работают с одним состоянием.

Отличие Props от State

Характеристика Props State
Кто владеет Родительский компонент Сам компонент
Можно изменять? ❌ Нет (readonly) ✅ Да (через setState)
Передаётся ли вниз? Да Да, как props
Вызывает перерисовку? Да (если изменился в родителе) Да (при вызове setState)
Для чего используется Передача данных Хранение динамических данных

Итог (что мы узнали)

Что узнали Как это работает
Props — входные данные Передаются от родителя, только для чтения
State — внутреннее состояние Живёт в компоненте, можно изменять
useState Хук для создания state
Обновление state Через сеттер, лучше через функцию
Не изменять напрямую Всегда создавать новый объект/массив
Подъём состояния Общий state у родителя

Задание для закрепления (на 7–10 минут)

  1. Создай компонент Counter с state count (начальное значение 0)
  2. Добавь две кнопки: «+1», «-1» и «Сбросить»
  3. Создай компонент Display, который принимает count через props и выводит текст: Текущее значение: {count}
  4. В App.jsx объедини оба компонента: Counter как родитель, Display как дочерний

Дополнительно: Добавь проверку, чтобы счёт не уходил в минус (при клике на «-1» не давать уйти ниже 0).

Проверка: Должен работать счётчик, который показывает число и не позволяет стать отрицательным. У вас должно получиться что-то похожее на показанное ниже.

Что дальше?

В следующем уроке разберём Conditional Rendering — как показывать разные элементы в зависимости от условий. Ты научишься делать интерфейсы, которые адаптируются под состояние приложения: показывать загрузку, сообщения об ошибках, переключать темы и многое другое. Это сделает твои приложения живыми и отзывчивыми.

Теги: