Signals — это фундаментальный механизм реактивности
во фреймворке Fresh, который позволяет отслеживать изменения состояния и
автоматически обновлять связанные с ним компоненты. В отличие от
традиционного управления состоянием через useState или
контекстные API, signals обеспечивают более тонкую реактивность,
минимизируя перерендеры и повышая производительность.
Для создания signal используется функция signal из
пакета @preact/signals:
import { signal } from "@preact/signals";
const counter = signal(0);
Здесь counter — это объект, который содержит текущее
значение value и методы для его обновления. Значение signal
хранится в свойстве value и может быть изменено
напрямую:
counter.value += 1;
При изменении значения все компоненты, которые используют этот signal, автоматически перерендериваются.
Signals можно использовать внутри Preact-компонентов как обычные
переменные. При рендеринге значение signal.value
отслеживается системой реактивности:
function Counter() {
return (
<div>
<p>Счетчик: {counter.value}</p>
<button onCl ick={() => counter.value++}>Увеличить</button>
</div>
);
}
Важно понимать, что signal автоматически подписывается на изменения. Компонент обновится только если изменится конкретный signal, используемый в рендере. Это уменьшает количество ненужных перерендеров, в отличие от глобального состояния.
Signals можно комбинировать и использовать для создания вычисляемых
значений. Для этого применяются функции computed и
производные signals:
import { computed } from "@preact/signals";
const doubleCounter = computed(() => counter.value * 2);
doubleCounter автоматически обновляется при изменении
counter.value. Это позволяет создавать реактивные
зависимости без ручного написания эффекта useEffect.
Для выполнения побочных эффектов при изменении signal используется
функция effect:
import { effect } from "@preact/signals";
effect(() => {
console.log(`Новое значение счетчика: ${counter.value}`);
});
Эффект будет вызван каждый раз, когда изменится
counter.value. Это особенно полезно для синхронизации
состояния с внешними API или локальным хранилищем.
Fresh использует signals для оптимизации рендеринга на сервере и клиенте. При SSR signal инициализируется на сервере и передается на клиент без потери состояния. Это позволяет:
Пример интеграции signals в Fresh-странице:
import { signal } from "@preact/signals";
import { HandlerContext } from "$fresh/server.ts";
const likes = signal(0);
export default function Page() {
return (
<div>
<h1>Лайки: {likes.value}</h1>
<button onCl ick={() => likes.value++}>Поставить лайк</button>
</div>
);
}
Состояние likes будет синхронизировано между серверным
рендером и клиентским обновлением.
Signals идеально подходят для управления формами и пользовательскими
событиями. Вместо сложной структуры useState можно
использовать signals для каждого поля формы:
const username = signal("");
const password = signal("");
function handleSubmit() {
console.log(username.value, password.value);
}
Изменение значения input напрямую обновляет signal:
<input
type="text"
value={username.value}
onIn put={(e) => (username.value = e.currentTarget.value)}
/>
value, чтобы гарантировать корректное отслеживание
изменений.Signals в Fresh формируют современный подход к управлению состоянием, обеспечивая высокую производительность, чистоту кода и гибкую реактивность без лишнего усложнения архитектуры приложения.