Props: передача данных

Props (properties) — механизм передачи данных от родительского компонента к дочернему; props иммутабельны внутри компонента-получателя.

Зачем нужно

Props — основной способ связи между компонентами в React. Понимание их работы необходимо с первых дней: через props передаются данные, обработчики событий, дочерние компоненты и конфигурация. Правильная типизация props через TypeScript позволяет поймать ошибки до запуска и делает API компонента самодокументируемым.

Где используется

  • Передача данных с уровня страницы в компоненты (список товаров → карточка товара)
  • Конфигурация переиспользуемых UI-компонентов (Button variant, Input placeholder)
  • Передача колбэков для обратной связи от дочернего к родительскому
  • Компоновка через children

Основы Props

// Компонент принимает props как аргумент
function UserCard({ name, email, role, onEdit }) {
  return (
    <div className="user-card">
      <h3>{name}</h3>
      <p>{email}</p>
      <span className={`badge badge--${role}`}>{role}</span>
      <button onClick={ => onEdit({ name, email })}>
        Редактировать
      </button>
    </div>
  );
}

// Использование — передача props как атрибутов
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <UserCard
          key={user.id}
          name={user.name}
          email={user.email}
          role={user.role}
          onEdit={(data) => console.log('Редактируем:', data)}
        />
      ))}
    </ul>
  );
}

TypeScript + props

// Типизация через interface
interface ButtonProps {
  children: React.ReactNode;
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}

function Button({
  children,
  variant = 'primary',  // значение по умолчанию
  size = 'md',
  disabled = false,
  onClick,
}: ButtonProps) {
  return (
    <button
      className={`btn btn--${variant} btn--${size}`}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

Паттерн: children и render props

// children — специальный проп для вложенного содержимого
function Card({ children, title }) {
  return (
    <div className="card">
      {title && <h2 className="card__title">{title}</h2>}
      <div className="card__body">{children}</div>
    </div>
  );
}

// Использование с children
<Card title="Профиль пользователя">
  <UserInfo user={currentUser} />
  <UserStats stats={userStats} />
</Card>

// Spread props — передача остальных пропсов
function Input({ label, error, ...inputProps }) {
  return (
    <label>
      {label}
      <input {...inputProps} />  {/* value, onChange, type и т.д. */}
      {error && <span className="error">{error}</span>}
    </label>
  );
}

Частые ошибки

  • Мутация propsprops.items.push(newItem) внутри компонента нарушает однонаправленный поток данных; для изменений используйте state.
  • Передача всего объекта вместо нужных полей<Card user={user} /> вместо <Card name={user.name} email={user.email} /> нарушает инкапсуляцию и усложняет переиспользование.
  • Пропуск key при рендере списковkey нужен при рендере массива компонентов, но это отдельный механизм, не обычный prop.
  • Слишком много props — если компонент принимает 10+ пропсов, это сигнал о нарушении принципа единственной ответственности.

Связанные темы

Ресурсы