Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
TypeScript
at sl/gitmirror
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576type ActionState<T> = | { kind: "idle" } | { kind: "loading" } | { kind: "ready"; value: T } | { kind: "failed"; error: string };type Operation<T, Args extends unknown[] = []> = (...args: Args) => Promise<T>;
const defaultError = (cause: unknown) => (cause instanceof Error ? cause.message : String(cause));
const create = <T, Args extends unknown[] = []>( operation: Operation<T, Args>, initial: ActionState<T>, toError: typeof defaultError) => { let state = $state<ActionState<T>>(initial); let revision = 0; let args: Args | undefined;
const run: Operation<void, Args> = async (...nextArgs) => { const currentRevision = ++revision; args = nextArgs; state = { kind: "loading" }; try { const value = await operation(...nextArgs); if (currentRevision !== revision) return; args = undefined; state = { kind: "ready", value }; } catch (cause) { if (currentRevision !== revision) return; args = undefined; state = { kind: "failed", error: toError(cause) }; } };
return { get data() { return state.kind === "ready" ? state.value : undefined; }, get error() { return state.kind === "failed" ? state.error : undefined; }, get loading() { return state.kind === "loading"; }, get args() { return state.kind === "loading" ? args : undefined; }, run, update(update: (current: T) => T): boolean { if (state.kind !== "ready") return false; revision++; state = { kind: "ready", value: update(state.value) }; return true; } };};
// loads run automatically and rerun when reactive values change:// const post = createLoad(() => api.getPost(id));//// actions only run when called:// const save = createAction(api.savePost);// await save.run(draft);//// both expose .data, .error, .loading, and .args.export const createAction = <T, Args extends unknown[] = []>( operation: Operation<T, Args>, toError: typeof defaultError = defaultError) => create(operation, { kind: "idle" }, toError);
export const createLoad = <T>(load: Operation<T>, toError: typeof defaultError = defaultError) => { const action = create(load, { kind: "loading" }, toError); $effect(() => void action.run()); return action;};