Компоненты
Компоненты являются строительными блоками для построения JSX разметки. Каждый компонент представляет собой функцию, реализующую тип PC (для синхронных компонентов) или APC (для асинхронных компонентов). Первым аргументом в такую функцию приходят параметры, а вторым - доступные утилиты PreffX.
Особенности реализации:
- Реактивность: Использует систему сигналов (
@preact/signals-core) для создания и отслеживания реактивных значений. Только такие значения вызывают перерисовку. - Управление жизненным циклом: Запускает колбеки при монтировании и удалении компонента и автоматически удаляет эффекты
- Передача утилит PreffX в качестве второго аргумента: Все, что необходимо, приходит в параметрах, из самого PreffX нужно импортировать только типы
- Поддержка асинхронных функций: Работает как с синхронными, так и с асинхронными функциями, автоматические перерисовывая DOM-дерево при разрешении промиса
Базовая реализация
Простейшая реализация компонента со счетчиком выглядит следующим образом:
import type { PC } from 'preffx';
const MyComponent: PC = (props, { signal, computed }) => {
const { initialCount = 0 } = props;
const count = signal(initialCount);
return (
<div>
<p>Счетчик: {count}</p>
<button onClick={() => count.value++}>Увеличить</button>
</div>
);
};
const App: PC = () => {
return <MyComponent
initialCount={5}
/>;
};Реактивность
Для обеспечения реактивности используются функции, реализованные поверх @preact/signals-core, например:
signal- создает реактивный сигнал для состояния,computed- вычисляет зависимые значения,effect- управляет побочными эффектами.
Эти и другие функции полностью реализуют поведение, описанное в документации Preact Signals.
Контекст компонента
Для каждого экземпляра компонента создается свой контекст, который расширяет контекст родителя. Это обычный объект, который можно взять из утилит:
import type { PC } from 'preffx';
const contextKey = 'ctx-counter';
const AnotherComponent: PC = (props, { context }) => {
// read context
const counter = context[contextKey];
return <span>
{counter}
</span>;
};
export const App: PC = (props, { signal, context }) => {
const counter = signal(0);
// modify context
context[contextKey] = counter;
return <p>
{valueFromContext}
<AnotherComponent />
</p>;
};Жизненный цикл
Каждый компонент может использовать утилиты жизненного цикла:
onMount- вызывается при монтировании компонента - после того, как его элементы будут добавлены в DOM-дерево;onDestroy- вызывается при удалении компонента - перед тем, как его элементы будут удалены из DOM-дерева
import type { PC } from 'preffx';
export const App: PC = (props, { onMount, onDestroy }) => {
const { count } = props;
onMount(() => {
// some mount logic
});
onDestroy(() => {
// some destroy logic
});
return <button
onClick={() => {
count.value += 1
}}
>
Count is {count}
</button>
};Генерация идентификаторов
Утилита id позволяет генерировать уникальные идентификаторы для использования внутри компонента:
import type { PC } from 'preffx';
export const App: PC = (props, { id }) => {
// get unique id
const inputId = id();
return <>
<label>
Password:
<input
type="password"
aria-describedby={inputId}
/>
</label>
<p id={inputId}>
The password should contain at least 18 characters
</p>
</>;
};Специальные компоненты
Среди утилит можно выделить специальные встроенные компоненты:
Catch- для обработки ошибок в компонентах,For- для рендеринга списков с поддержкой реактивности,Defer- для отложенного рендеринга значений, которые вычисляются асинхронно,Portal- для рендеринга элементов вне корня PreffX