Определение и использование пропсов

Понятие пропсов

Пропсы (props, от properties) представляют собой способ передачи данных от родительского компонента к дочернему. Они являются неизменяемыми внутри компонента: компонент получает пропсы и использует их для рендеринга интерфейса или передачи дальше. В отличие от состояния (state), которое может меняться внутри компонента, пропсы служат для конфигурации и передачи информации извне.

Пример базового компонента с пропсами:

import { h } from 'preact';

function Button({ label, onClick }) {
    return (
        <button onCl ick={onClick}>
            {label}
        </button>
    );
}

В этом примере label и onClick — это пропсы. Они определяются в момент использования компонента:

<Button label="Нажми меня" onCl ick={() => alert('Клик!')} />

Деструктуризация пропсов

Preact поддерживает деструктуризацию пропсов прямо в сигнатуре функции компонента, что делает код более читаемым:

function Card({ title, content, footer }) {
    return (
        <div className="card">
            <h2>{title}</h2>
            <p>{content}</p>
            <div className="card-footer">{footer}</div>
        </div>
    );
}

Такой подход упрощает доступ к отдельным пропсам без необходимости писать props.title, props.content и т.д.

Пропсы по умолчанию

Чтобы компонент корректно работал даже при отсутствии некоторых пропсов, Preact позволяет задавать значения по умолчанию. Для функциональных компонентов можно использовать стандартные возможности Jav * aScript:

function Badge({ text = 'Новый', color = 'blue' }) {
    return <span style={{ backgroundColor: color }}>{text}</span>;
}

Если компонент вызывается без пропсов:

<Badge />

Он всё равно отобразит «Новый» с синим фоном.

Пропсы и типизация

Хотя Preact не имеет встроенной строгой типизации, TypeScript позволяет описывать интерфейсы пропсов, что обеспечивает безопасность и автодополнение:

interface UserCardProps {
    name: string;
    age?: number;
}

function UserCard({ name, age }: UserCardProps) {
    return (
        <div>
            <h3>{name}</h3>
            {age && <p>Возраст: {age}</p>}
        </div>
    );
}

Символ ? в интерфейсе означает, что пропс age необязательный. Такой подход особенно полезен при работе с крупными приложениями, где компоненты имеют большое количество параметров.

Передача функций через пропсы

Пропсы позволяют передавать не только данные, но и функции. Это основной способ обработки событий в дочерних компонентах:

function Counter({ onIncrement }) {
    return (
        <button onCl ick={onIncrement}>
            Увеличить
        </button>
    );
}

function App() {
    const handleIncrement = () => console.log('Счётчик увеличен');
    return <Counter onIncrem ent={handleIncrement} />;
}

Функции в пропсах дают возможность управлять состоянием родительского компонента из дочернего, сохраняя архитектуру приложения чистой и предсказуемой.

Пропсы и JSX

В Preact компоненты, вызываемые через JSX, могут принимать любые значения как пропсы: строки, числа, массивы, объекты и даже JSX-элементы:

function List({ items }) {
    return (
        <ul>
            {items.map(item => <li key={item.id}>{item.name}</li>)}
        </ul>
    );
}

<List items={[{ id: 1, name: 'Элемент 1' }, { id: 2, name: 'Элемент 2' }]} />

Важно использовать уникальные ключи (key) при рендеринге списков, чтобы Preact корректно отслеживал изменения и оптимизировал обновления DOM.

Пропсы и spread-оператор

Для передачи большого количества пропсов удобно использовать spread-оператор:

const buttonProps = { label: 'Сохранить', onClick: () => console.log('Сохранено') };

<Button {...buttonProps} />

Это особенно полезно при работе с компонентами, которые требуют множества параметров, и позволяет избежать явного перечисления каждого пропса.

Изменяемые объекты и массивы в пропсах

Хотя пропсы сами по себе неизменяемы, переданные объекты и массивы могут быть модифицированы внутри компонента, что может привести к непредсказуемым результатам. Рекомендуется всегда использовать копии данных или методы, возвращающие новые объекты:

function Items({ list }) {
    const newList = [...list, { id: 3, name: 'Новый элемент' }];
    return newList.map(item => <div key={item.id}>{item.name}</div>);
}

Это предотвращает нежелательные побочные эффекты при работе с пропсами.

Комбинирование пропсов и состояния

Часто компоненты используют одновременно пропсы и локальное состояние. Пропсы задают начальные значения или конфигурацию, а состояние управляет динамическими изменениями:

function Toggle({ initial = false }) {
    const [isOn, setIsOn] = useState(initial);

    return (
        <button onCl ick={() => setIsOn(!isOn)}>
            {isOn ? 'Вкл' : 'Выкл'}
        </button>
    );
}

initial — это пропс, задающий стартовое состояние. Дальнейшие изменения происходят через useState, не затрагивая исходный пропс.

Композиция компонентов через пропсы

Пропсы позволяют передавать компоненты как значения, что упрощает создание универсальных и переиспользуемых компонентов:

function Modal({ header, body, footer }) {
    return (
        <div className="modal">
            <div className="modal-header">{header}</div>
            <div className="modal-body">{body}</div>
            <div className="modal-footer">{footer}</div>
        </div>
    );
}

<Modal
    header={<h2>Заголовок</h2>}
    body={<p>Содержимое модального окна</p>}
    footer={<button>Закрыть</button>}
/>

Такой подход делает интерфейсы гибкими и позволяет легко менять содержимое модальных окон, карточек и других компонентов без изменения их внутренней логики.