[]previous and next page

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#

ts
import { useAction } from "@shadow-js/core";

Signature#

ts
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 dispatch rejects 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#

ts
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());