useAction
A state machine for a form-style action: dispatch(...args) runs action(previous, ...args), tracks whether it is pending, and commits its result.
A state machine for a form-style action: dispatch(...args) runs action(previous, ...args),
tracks whether it is pending, and commits its result. The ShadowJS form of React's
useActionState (state, dispatch, pending). previous is the last committed state.
Only the latest dispatch commits: when two actions overlap, a slower result that settles after a
newer dispatch is discarded, so the screen never goes back to an older answer. A failure does not
change the state; it clears pending and is sent to the owner's error handler (onError), so an
error boundary can show it. Without an owner the returned promise rejects instead.
Import#
import { useAction } from "@shadow-js/core";
Signature#
function useAction<S, A extends unknown[]>(
action: (previous: S, ...args: A) => S | PromiseLike<S>,
initialState: S,
): [state: Accessor<S>, dispatch: (...args: A) => Promise<void>, pending: Accessor<boolean>]
Parameters#
| Name | Description |
|---|---|
action |
(previous, ...args) => next, synchronous or async. It runs untracked. |
initialState |
The state before the first dispatch. |
Returns#
[state, dispatch, pending]. A synchronous result commits at once; pending is true
only while a returned promise is unsettled. dispatch returns a promise that settles when this
call has finished, whether it committed or not.
Throws#
- Nothing synchronously. Without an owner, the promise returned by
dispatchrejects with the action's error. With an owner, the error goes to its error handler, or is reported as an uncaught error (reportError) when no handler is registered above it.
Examples#
import { useAction } from "@shadow-js/core";
const [message, send, sending] = useAction(async (_prev: string, text: string) => {
await fetch("/api/messages", { method: "POST", body: text });
return `sent: ${text}`;
}, "");
void send("hello");
console.log(sending(), message());