useStatus is a hook for managing a discrete process status: 'initial', 'pending', 'success', 'error'. It returns an object that combines the current flags (isPending, isSuccess, isError), an optional error (only in the 'error' state), and control methods: setPending, setSuccess, setError, reset, setStatus.
function useStatus(defaultStatus?: Status): UseStatusReturn;-
Parameters
defaultStatus?: Status— initial status; defaults to'initial'.
-
Returns:
UseStatusReturn— a combined object:- flags:
isPending,isSuccess,isError; errorfield (only in'error', otherwisenull);- control methods:
setPending(),setSuccess(),setError(error?),reset(),setStatus(status).
- flags:
import { useStatus } from '@webeach/react-hooks/useStatus';
export type SaveButtonProps = {
save: () => Promise<void>;
};
export function SaveButton(props: SaveButtonProps) {
const { save } = props;
const status = useStatus();
const handleClick = async () => {
status.setPending();
try {
await save();
status.setSuccess();
} catch (error) {
// `error` can be anything — normalize to ErrorLike
const message = error instanceof Error ? error.message : String(error);
status.setError({ message });
}
};
return (
<>
<button onClick={handleClick} disabled={status.isPending}>
{status.isPending ? 'Saving…' : 'Save'}
</button>
{status.error !== null && <div role="alert">{status.error.message}</div>}
</>
);
}const status = useStatus('success');
// …
status.reset(); // → 'initial'const status = useStatus();
status.setStatus('pending');
// …
status.setStatus('success');-
Flags and error
- The flags
isPending,isSuccess,isErrorare mutually exclusive.erroris set only in the'error'state (otherwisenull).
- The flags
-
setError(error?)- Switches the status to
'error'and stores the provided error object (ornullif omitted). In the UI, check bothisErroranderror.
- Switches the status to
-
setPending()/setSuccess()/reset()- Move the status to
'pending'/'success'/'initial'respectively. In all cases,errorbecomesnull.
- Move the status to
-
setStatus(status)- Directly set one of the allowed statuses. Useful when the transition is dictated by external logic.
-
UI patterns compatibility
- Handy for disabling elements (
disabled={status.isPending}), showing progress/errors, and resetting state on events (status.reset()).
- Handy for disabling elements (
- API requests, data loading/saving, long‑running operations.
- Submit/Save buttons, forms, modals with async logic.
- Any process with common stages: waiting → success → error.
- If you need a complex state machine (multiple branches/sub‑statuses) — consider
useReduceror a finite‑state machine. - If the status can be derived from the data itself (e.g., “success when the list is not empty”) — store only the minimal state.
-
Passing a string instead of
ErrorLikesetErrorexpects an object with amessagefield. Normalize the value:setError({ message: String(error) }).
-
Rendering error text without checking the status
- Check
status.error !== nullbefore rendering the message.
- Check
-
Forgetting to switch to
'pending'- Call
status.setPending()before starting an async operation; otherwise the UI may not reflect the waiting state.
- Call
-
Mixing manual and automatic logic
- If you use
setStatusdirectly, make sure it doesn’t conflict with automatic calls tosetPending/Success/Errorin your handlers.
- If you use
Exported types
UseStatusReturn- Combines status flags, possible error, and control methods.
- Fields:
isPending: boolean—truewhile the operation is in progress.isSuccess: boolean—truewhen the operation has completed successfully.isError: boolean—truewhen an error has occurred.error: ErrorLike | null— error object (only ifisError: true).- Methods:
reset(): void— sets status to'initial'.setError(error?: ErrorLike | null): void— sets status to'error'and stores the error.setPending(): void— sets status to'pending'.setSuccess(): void— sets status to'success'.setStatus(status: Status): void— sets the status directly.