Higher-Order Components (HOC) представляют собой функцию, которая принимает компонент и возвращает новый компонент с расширенной функциональностью. В экосистеме Svelte и SvelteKit подход к HOC отличается от привычных практик в React, но суть остаётся прежней: повторное использование логики и композиция поведения компонентов.
HOC не изменяет исходный компонент напрямую. Вместо этого он оборачивает его в другой компонент, добавляя дополнительные свойства, методы или обработку событий. В Svelte это достигается через:
onMount и
реактивных переменных.Пример базового HOC для логирования пропсов:
<!-- withLogger.svelte -->
<script>
export let WrappedComponent;
export let props;
import { onMount } from 'svelte';
onMount(() => {
console.log('Props:', props);
});
</script>
<svelte:component this={WrappedComponent} {...props} />
Использование:
<script>
import Button from './Button.svelte';
import WithLogger from './withLogger.svelte';
</script>
<WithLogger WrappedComponent={Button} props={{ text: 'Click me' }} />
Здесь WithLogger добавляет поведение логирования к
любому компоненту без изменения его исходного кода.
HOC часто используют для добавления состояния или обработки данных:
<!-- withCounter.svelte -->
<script>
export let WrappedComponent;
let count = 0;
const increment = () => count += 1;
</script>
<svelte:component this={WrappedComponent} {count} {increment} />
Использование позволяет любому компоненту получать счётчик и функцию увеличения без дублирования логики.
HOC удобно применять для проверки прав пользователя перед рендерингом компонента:
<script>
export let WrappedComponent;
export let user;
let authorized = false;
$: authorized = user?.role === 'admin';
</script>
{#if authorized}
<svelte:component this={WrappedComponent} />
{:else}
<p>Доступ запрещён</p>
{/if}
Таким образом, можно централизованно управлять доступом ко многим компонентам.
HOC может инкапсулировать логику работы с API, предоставляя компоненту уже готовые данные:
<script>
import { onMount } from 'svelte';
export let WrappedComponent;
export let endpoint;
let data = null;
let loading = true;
onMount(async () => {
const res = await fetch(endpoint);
data = await res.json();
loading = false;
});
</script>
{#if loading}
<p>Загрузка данных...</p>
{:else}
<svelte:component this={WrappedComponent} {data} />
{/if}
Это позволяет создавать универсальные компоненты с поддержкой загрузки и управления состоянием данных.
props.children.return внутри функции HOC — используется
<svelte:component>.export let для передачи всех необходимых
пропсов.HOC можно цепочечно применять для одного компонента:
<WithLogger WrappedComponent={WithCounter WrappedComponent={Button}} props={{ text: 'Click me' }} />
Порядок применения важен: HOC, оборачивающий внутренний компонент, получает пропсы, уже обработанные предыдущим HOC. В SvelteKit такая композиция позволяет строить мощные UI-обертки без избыточного кода.
Многие Svelte UI библиотеки (например, Svelte Material UI, Shadcn UI) предоставляют базовые компоненты, которые легко расширять через HOC:
Использование HOC в сочетании с UI библиотеками упрощает создание унифицированного интерфейса с минимальной дубликацией кода.