-
-
Notifications
You must be signed in to change notification settings - Fork 0
Forms State And Data
Status: Implemented across @effuse/use, @effuse/store, and
@effuse/query. Compatibility remains experimental.
useForm creates reactive field values, errors, validity, submission state,
and validation behavior.
const form = useForm({
initialValues: { email: '' },
validate: {
email: [required(), email()],
},
onSubmit: async (values) => {
await register(values);
},
});Use labels, native controls, and explicit error output in templates. Server validation should be mapped into the same field/error model rather than stored in unrelated component state.
@effuse/store provides reactive state, selectors, slices, actions, async
actions, cancellation, persistence-related hooks, and Effect-based execution.
const cart = createStore('cart', {
items: [] as CartItem[],
add(item: CartItem) {
this.items.value = [...this.items.value, item];
},
});For capability-owned state, expose the store through a layer service or derived props. Components should bind to the layer rather than rely on ambient string lookup as the primary architecture.
@effuse/query provides query clients, caches, observers, retries, mutations,
infinite queries, query options, key factories, and reactive cache metadata.
const users = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then((r) => r.json()),
});Server state belongs in query caches; durable application commands and capabilities belong in layers. A query can call a manifest client instead of hard-coding a URL.
@effuse/i18n supports typed translations, locale state, nested keys,
interpolation, and pluralization. Install its runtime once and consume
translations through the package hooks or an application layer boundary.
For server-side rendering, prefer request-scoped instances over the global
singleton so concurrent requests never share locale state. createI18nInstance
builds an instance without registering it globally (locale detection and
persistence are off by default, since the locale must come from the request),
resolveLocale(header, available, fallback) negotiates an Accept-Language
header against the locales you ship, and withI18n(instance, () => ...) binds
the instance for one render so getI18n, t, and useTranslation resolve
against it:
const locale = resolveLocale(request.headers['accept-language'], ['en', 'es'], 'en');
const i18n = createI18nInstance({ defaultLocale: locale, translations });
const html = withI18n(i18n, () => renderApp());@effuse/ink renders reactive Markdown and supports mapped Effuse components.
Treat Markdown input as content, and apply an application security policy when
content is not trusted.