Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Передача всех props компоненту в React
1. Оператор распаковки (...) для props
Оператор spread позволяет передать все свойства объекта как отдельные props:
// Простой объект с свойствами
const buttonProps = {
type: 'button',
className: 'btn btn-primary',
onClick: handleClick,
disabled: false
};
// Передаем все props сразу
<button {...buttonProps}>Нажми меня</button>
// Эквивалентно:
<button
type="button"
className="btn btn-primary"
onClick={handleClick}
disabled={false}
>
Нажми меня
</button>
2. Распаковка props в компоненте
// Компонент получает объект props
function Button(props) {
return (
<button {...props}>
{props.children}
</button>
);
}
// Использование
const config = {
className: 'primary',
onClick: () => alert('Clicked'),
type: 'submit'
};
<Button {...config}>Отправить</Button>
3. Деструктуризация + распаковка
// Выделяем известные props, остальное в rest
function Input({ value, onChange, ...rest }) {
return (
<input
value={value}
onChange={onChange}
{...rest} // Все оставшиеся props (placeholder, type, required и т.д.)
/>
);
}
// Использование
const inputProps = {
placeholder: 'Введите текст',
type: 'email',
required: true,
maxLength: 50,
aria-label: 'Email input'
};
<Input value={email} onChange={handleChange} {...inputProps} />
4. Расширение props для дочерних компонентов
function Card({ title, children, ...props }) {
return (
<div className="card" {...props}>
<div className="card-header">{title}</div>
<div className="card-body">{children}</div>
</div>
);
}
// Использование
<Card
title="Информация"
id="user-card"
data-testid="card-1"
className="custom-card"
>
Содержимое карточки
</Card>
5. Объединение props из разных источников
function Button({ variant = 'primary', size = 'md', ...rest }) {
// Базовые стили в зависимости от варианта
const baseClass = `btn btn-${variant} btn-${size}`;
// Объединяем с переданным классом
const finalClass = rest.className
? `${baseClass} ${rest.className}`
: baseClass;
return (
<button {...rest} className={finalClass}>
{rest.children}
</button>
);
}
// Использование
<Button
variant="secondary"
size="lg"
className="custom-button"
onClick={handleClick}
>
Большая вторичная кнопка
</Button>
6. TypeScript типизация props
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
}
function Button({
variant = 'primary',
size = 'md',
className,
...rest
}: ButtonProps) {
const classes = `btn btn-${variant} btn-${size} ${className || ''}`;
return (
<button className={classes} {...rest} />
);
}
// Типизирование с правильной проверкой
const props = {
type: 'submit' as const,
onClick: () => {},
disabled: false
};
<Button {...props}>Отправить</Button>
7. Передача props в HOC (Higher-Order Component)
// HOC, который оборачивает компонент
function withLoading(Component) {
return function WrappedComponent({ isLoading, ...rest }) {
if (isLoading) {
return <div>Загрузка...</div>;
}
// Передаем все остальные props оригинальному компоненту
return <Component {...rest} />;
};
}
// Использование
const UserList = ({ users }) => (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
const UserListWithLoading = withLoading(UserList);
<UserListWithLoading isLoading={false} users={[...]} />
8. Условная передача props
function FormField({ required, ...rest }) {
const props = {
...rest,
required // Явно указываем required
};
// Добавляем aria-required только если required=true
if (required) {
props['aria-required'] = true;
}
return <input {...props} />;
}
// Или более элегантно:
function FormField({ required, ...rest }) {
return (
<input
{...rest}
required={required}
aria-required={required || undefined}
/>
);
}
9. React.forwardRef с распаковкой props
const Input = React.forwardRef(({ label, error, ...rest }, ref) => {
return (
<div className="form-group">
{label && <label>{label}</label>}
<input ref={ref} {...rest} />
{error && <span className="error">{error}</span>}
</div>
);
});
// Использование
const inputRef = useRef(null);
<Input
ref={inputRef}
label="Email"
type="email"
placeholder="user@example.com"
error={emailError}
/>
10. Использование cn() для условных классов
import { cn } from '@/lib/utils';
function Button({ variant = 'primary', size = 'md', className, ...rest }) {
return (
<button
className={cn(
'btn',
{
'btn-primary': variant === 'primary',
'btn-secondary': variant === 'secondary',
'btn-sm': size === 'sm',
'btn-md': size === 'md',
'btn-lg': size === 'lg'
},
className
)}
{...rest}
/>
);
}
11. Compound Components паттерн
function Form({ ...props }) {
return <form {...props} />;
}
function FormGroup({ ...props }) {
return <fieldset {...props} />;
}
function FormInput({ label, ...props }) {
return (
<div className="form-group">
{label && <label>{label}</label>}
<input {...props} />
</div>
);
}
function FormButton({ ...props }) {
return <button type="submit" {...props} />;
}
// Использование
<Form onSubmit={handleSubmit}>
<FormGroup>
<FormInput label="Имя" name="name" type="text" />
<FormInput label="Email" name="email" type="email" />
<FormButton>Отправить</FormButton>
</FormGroup>
</Form>
12. Практический пример: обертка над HTML элементом
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: 'default' | 'elevated' | 'outlined';
padding?: 'sm' | 'md' | 'lg';
}
function Card({
variant = 'default',
padding = 'md',
className,
children,
...rest
}: CardProps) {
return (
<div
className={cn(
'rounded-lg',
{
'shadow-none': variant === 'default',
'shadow-md': variant === 'elevated',
'border': variant === 'outlined',
'p-2': padding === 'sm',
'p-4': padding === 'md',
'p-6': padding === 'lg'
},
className
)}
{...rest}
>
{children}
</div>
);
}
// Использование
<Card
variant="elevated"
padding="lg"
id="user-card"
data-testid="card"
onClick={handleClick}
>
Содержимое карточки
</Card>
Что ВАЖНО помнить
- Порядок имеет значение: если передать пропс дважды, последний перезапишет предыдущий:
<Component {...props} onClick={newHandler} /> // newHandler будет использован
<Component onClick={newHandler} {...props} /> // props.onClick будет использован
- Не забывай про children: при использовании rest параметров children туда не попадет:
function Component({ ...rest }) {
// rest содержит все props КРОМЕ children
return <div>{rest.children}</div>; // undefined!
}
// Правильно:
function Component({ children, ...rest }) {
return <div {...rest}>{children}</div>;
}
- Типизируй правильно: используй HTMLAttributes<T> для получения типов всех HTML атрибутов
Итоги
Spread оператор (...) для props:
- Упрощает передачу множества пропсов
- Работает для конфигурирования компонентов
- Стандартный паттерн в React
- Комбинируй с деструктуризацией для выделения известных props
- Помни про порядок передачи для избежания конфликтов