Перейти к содержимому
GitHubXDiscord

createNamedHooks

Стабильный · с 0.1.0

Возвращает прокси из хуков, специализированных под один триггер. Вместо того чтобы везде писать useEvent(messageTrigger, 'new-message'), ты зовёшь useNewMessageEvent(), и система типов уже знает, какой триггер и какой порт. То же для useUserCondition(getter, deps?) и useShowToastAction(handler).

Прокси ленивый и кэшируемый: каждое имя хука парсится один раз, соответствующий делегатор строится один раз, последующие рендеры берут из кэша.

import { createNamedHooks } from '@triggery/react';
function createNamedHooks<S extends TriggerSchema>(
  trigger: Trigger<S>,
): NamedHooks<S>;
ПараметрТипОписание
triggerTrigger<S>Триггер, к которому привязываются хуки.

Прокси-объект, типизированный как NamedHooks<S> — объединение:

Поле исходной схемыСгенерированный хукСигнатура
events: { 'new-message': T }useNewMessageEvent() => (payload: T) => void
conditions: { user: U }useUserCondition(getter: () => U, deps?: readonly unknown[]) => void
actions: { showToast: P }useShowToastAction(handler: (payload: P) => void | Promise<void>) => void

Конвертация имён: kebab-case и camelCase ключи оба round-trip’ятся через PascalCase. 'new-message'NewMessage, 'user'User, 'showToast'ShowToast.

import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
import { createNamedHooksfunction createNamedHooks<S extends TriggerSchema>(trigger: Trigger<S>): NamedHooks<S>
Build the named-hooks proxy for a trigger. For a schema with `events: { 'new-message' }`, `conditions: { user }` and `actions: { showToast }` this returns: useNewMessageEvent -> () => fire useUserCondition -> (getter, deps?) => void useShowToastAction -> (handler) => void Names are derived from string keys via `kebab-case -> PascalCase`: - `'new-message'` -> `useNewMessageEvent` - `'user'` -> `useUserCondition` - `'showToast'` -> `useShowToastAction` Use it like: export const { useNewMessageEvent, useUserCondition, useShowToastAction } = createNamedHooks(messageTrigger); Implementation detail: the underlying object is a `Proxy` keyed by the hook name. Each lookup synthesizes a hook that delegates to `useEvent` / `useCondition` / `useAction` with the right port name.
} from '@triggery/react';
type Message
type Message = {
    author: string;
    text: string;
}
= { authorauthor: string: string; texttext: string: string };
export const messageTrigger
const messageTrigger: Trigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>
= createTrigger
createTrigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>(config: CreateTriggerConfig<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    'new-message': Message;
}
: { 'new-message': Message
type Message = {
    author: string;
    text: string;
}
};
conditions
conditions: {
    user: {
        id: string;
        name: string;
    } | null;
}
: { user
user: {
    id: string;
    name: string;
} | null
: { idid: string: string; namename: string: string } | null };
actions
actions: {
    showToast: {
        title: string;
        body: string;
    };
}
: { showToast
showToast: {
    title: string;
    body: string;
}
: { titletitle: string: string; bodybody: string: string } };
}>({ idid: string: 'chat:new-message', eventsevents: readonly "new-message"[]: ['new-message'], requiredrequired?: readonly "user"[] | undefined
Required condition keys. The trigger will not run unless all of them are registered.
: ['user'],
handler
handler: TriggerHandler<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}, never>
({ event
event: {
    readonly name: "new-message";
    readonly payload: Message;
}
, conditions
conditions: ConditionsCtx<{
    user: {
        id: string;
        name: string;
    } | null;
}, never>
, actions
actions: ActionsCtx<{
    showToast: {
        title: string;
        body: string;
    };
}>
}) {
actions
actions: ActionsCtx<{
    showToast: {
        title: string;
        body: string;
    };
}>
.showToast
showToast?: ((payload: {
    title: string;
    body: string;
}) => void) | undefined
?.({
titletitle: string: conditions
conditions: ConditionsCtx<{
    user: {
        id: string;
        name: string;
    } | null;
}, never>
.user
user?: {
    id: string;
    name: string;
} | null | undefined
?.namename: string | undefined ?? '',
bodybody: string: event
event: {
    readonly name: "new-message";
    readonly payload: Message;
}
.payloadpayload: Message.texttext: string,
}); }, }); export const { useNewMessageEventconst useNewMessageEvent: EventHook<Message>, useUserCondition
const useUserCondition: ConditionHook<{
    id: string;
    name: string;
} | null>
,
useShowToastAction
const useShowToastAction: ActionHook<{
    title: string;
    body: string;
}>
,
} = createNamedHooks
createNamedHooks<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>(trigger: Trigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>): NamedHooks<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>
Build the named-hooks proxy for a trigger. For a schema with `events: { 'new-message' }`, `conditions: { user }` and `actions: { showToast }` this returns: useNewMessageEvent -> () => fire useUserCondition -> (getter, deps?) => void useShowToastAction -> (handler) => void Names are derived from string keys via `kebab-case -> PascalCase`: - `'new-message'` -> `useNewMessageEvent` - `'user'` -> `useUserCondition` - `'showToast'` -> `useShowToastAction` Use it like: export const { useNewMessageEvent, useUserCondition, useShowToastAction } = createNamedHooks(messageTrigger); Implementation detail: the underlying object is a `Proxy` keyed by the hook name. Each lookup synthesizes a hook that delegates to `useEvent` / `useCondition` / `useAction` with the right port name.
(messageTrigger
const messageTrigger: Trigger<{
    events: {
        "new-message": Message;
    };
    conditions: {
        user: {
            id: string;
            name: string;
        } | null;
    };
    actions: {
        showToast: {
            title: string;
            body: string;
        };
    };
}>
);
import { useEffect } from 'react';
import {
  useNewMessageEvent,
  useUserCondition,
  useShowToastAction,
} from '../triggers/message.trigger';

function Producer({ socket }: { socket: WebSocket }) {
  const fire = useNewMessageEvent();
  useEffect(() => {
    socket.addEventListener('message', e => fire(JSON.parse(e.data)));
  }, [socket, fire]);
  return null;
}

function UserProvider({ user }: { user: { id: string; name: string } | null }) {
  useUserCondition(() => user, [user]);
  return null;
}

function Toaster() {
  useShowToastAction(({ title, body }) => console.log('toast', title, body));
  return null;
}

Экспортировать всё не обязательно:

import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
import { createNamedHooksfunction createNamedHooks<S extends TriggerSchema>(trigger: Trigger<S>): NamedHooks<S>
Build the named-hooks proxy for a trigger. For a schema with `events: { 'new-message' }`, `conditions: { user }` and `actions: { showToast }` this returns: useNewMessageEvent -> () => fire useUserCondition -> (getter, deps?) => void useShowToastAction -> (handler) => void Names are derived from string keys via `kebab-case -> PascalCase`: - `'new-message'` -> `useNewMessageEvent` - `'user'` -> `useUserCondition` - `'showToast'` -> `useShowToastAction` Use it like: export const { useNewMessageEvent, useUserCondition, useShowToastAction } = createNamedHooks(messageTrigger); Implementation detail: the underlying object is a `Proxy` keyed by the hook name. Each lookup synthesizes a hook that delegates to `useEvent` / `useCondition` / `useAction` with the right port name.
} from '@triggery/react';
const trigger
const trigger: Trigger<{
    events: {
        ping: void;
        pong: void;
    };
}>
= createTrigger
createTrigger<{
    events: {
        ping: void;
        pong: void;
    };
}>(config: CreateTriggerConfig<{
    events: {
        ping: void;
        pong: void;
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        ping: void;
        pong: void;
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    ping: void;
    pong: void;
}
: { pingping: void: void; pongpong: void: void };
}>({ idid: string: 'x', eventsevents: readonly ("ping" | "pong")[]: ['ping', 'pong'], handler
handler: TriggerHandler<{
    events: {
        ping: void;
        pong: void;
    };
}, never>
() {},
}); // Pull only the hook you use. export const { usePingEventconst usePingEvent: EventHook<void> } = createNamedHooks
createNamedHooks<{
    events: {
        ping: void;
        pong: void;
    };
}>(trigger: Trigger<{
    events: {
        ping: void;
        pong: void;
    };
}>): NamedHooks<{
    events: {
        ping: void;
        pong: void;
    };
}>
Build the named-hooks proxy for a trigger. For a schema with `events: { 'new-message' }`, `conditions: { user }` and `actions: { showToast }` this returns: useNewMessageEvent -> () => fire useUserCondition -> (getter, deps?) => void useShowToastAction -> (handler) => void Names are derived from string keys via `kebab-case -> PascalCase`: - `'new-message'` -> `useNewMessageEvent` - `'user'` -> `useUserCondition` - `'showToast'` -> `useShowToastAction` Use it like: export const { useNewMessageEvent, useUserCondition, useShowToastAction } = createNamedHooks(messageTrigger); Implementation detail: the underlying object is a `Proxy` keyed by the hook name. Each lookup synthesizes a hook that delegates to `useEvent` / `useCondition` / `useAction` with the right port name.
(trigger
const trigger: Trigger<{
    events: {
        ping: void;
        pong: void;
    };
}>
);