craftEffect#
An effect that can resolve craft dependencies with yield*.
Use it when a side effect needs a service. Not as a way to sync state — if a value is a function of another, derive it with computed instead of writing it from an effect.
Import#
import { craftEffect } from '@craft-ts/core';
craftUse(craftEffect('myEffect', function* () {
const counter = yield* Counter();
// do some stuff
}));
Resource triggers#
In generator code, primitive triggers are yieldable and must be consumed with yield*:
function* submit(term: string) {
yield* searchQuery.call(term);
yield* saveMutation.mutate({ term });
yield* validateProcess.method(term);
}
Imperative triggers from ordinary UI callbacks remain valid:
button({ click: () => saveMutation.mutate({ term: input() }) }, 'Save');
Do not use those triggers as dependencies of a craftEffect. Prefer a declarative params signal, a source$, or a mutation/query insertion. The craft-ts/no-imperative-craft-resource-trigger rule also follows a craftGen, so wrapping the call does not bypass the restriction:
const triggerSearch = craftGen(function* (term: string) {
yield* searchQuery.call(term);
});
craftUse(craftEffect('load', function* () {
yield* triggerSearch(input()); // forbidden: indirect imperative trigger
}));
Use a reactive query instead when the data depends on a signal:
const user = yield* query('user', {
params: userId,
loader: ({ params }) => fetchUser(params),
});
See Also#
Local state — deriving instead of writing from an effect
Architecture rules —
assertCraftEffectNoNetworkwhen an effect calls HTTP or a mutation,assertCraftEffectNoImperativeSyncwhen it writes astate/source$or triggers a query/mutation