alepha@docs:~/framework/docs/reference/react-hooks$
cat useAction.md | pretty2 min read
Last commit:
#useAction
#Import
typescript
1import { useAction } from "alepha/react";
#Overview
Hook for handling async actions with automatic error handling and event emission.
The handler takes an ActionContext FIRST, then the arguments run()
was given: handler: async ({ signal }, id: string) => ....
run() never rejects. It resolves one RunResult:
{ ok: true, value }: the handler returnedvalue.{ ok: false, reason: "error", error }: the handler threwerror(also inerrorstate and emitted asreact:action:error).{ ok: false, reason: "dropped" }: refused because a run was already in flight, or a debounced call replaced by a newer one.{ ok: false, reason: "aborted" }: cancelled bycancel(), an unmount or a newer run.
So a follow-up branches on the result: if ((await save.run()).ok) close().
By default, prevents concurrent executions - if an action is running and you call it again,
the second call is dropped. Use debounce option to delay execution instead.
Emits lifecycle events:
react:action:begin- When action startsreact:action:success- When action completes successfullyreact:action:error- When action throws an errorreact:action:end- Always emitted at the end
#Examples
Basic usage
tsx
1const action = useAction( 2 { 3 handler: async (_ctx, data: Data) => { 4 await api.save(data); 5 }, 6 }, 7 [], 8); 9 10<button onClick={() => action.run(data)} disabled={action.loading}>11 Save12</button>;
With debounce (search input)
tsx
1const search = useAction( 2 { 3 handler: async (_ctx, query: string) => { 4 await api.search(query); 5 }, 6 debounce: 300, // Wait 300ms after last call 7 }, 8 [], 9);10 11<input onChange={(e) => search.run(e.target.value)} />;
Run on component mount
tsx
1const fetchData = useAction( 2 { 3 handler: async () => { 4 const data = await api.getData(); 5 return data; 6 }, 7 runOnInit: true, // Runs once when component mounts 8 }, 9 [],10);
Run periodically (polling)
tsx
1const pollStatus = useAction( 2 { 3 handler: async () => { 4 const status = await api.getStatus(); 5 return status; 6 }, 7 runEvery: 5000, // Run every 5 seconds 8 }, 9 [],10);11 12// Or with duration tuple13const pollStatus = useAction(14 {15 handler: async () => {16 const status = await api.getStatus();17 return status;18 },19 runEvery: [30, "seconds"], // Run every 30 seconds20 },21 [],22);
With AbortController
tsx
1const fetch = useAction( 2 { 3 handler: async ({ signal }, url: string) => { 4 const response = await fetch(url, { signal }); 5 return response.json(); 6 }, 7 }, 8 [], 9);10// Automatically cancelled on unmount or when new request starts
With error handling
tsx
1const deleteAction = useAction( 2 { 3 handler: async (_ctx, id: string) => { 4 await api.delete(id); 5 }, 6 onError: (error) => { 7 if (error.code === "NOT_FOUND") { 8 // Custom error handling 9 }10 },11 },12 [],13);14 15{16 deleteAction.error && <div>Error: {deleteAction.error.message}</div>;17}
Global error handling
tsx
1// In your root app setup2alepha.events.on("react:action:error", ({ error }) => {3 toast.danger(error.message);4 Sentry.captureException(error);5});