React Commands
A React component sends commands by injecting the active container's CommandBus, and registers handlers while the component is mounted with useOnCommand.
Register the Plugin
Commands use the active container's CommandBus, which exists only when CommandsPlugin is registered in your provider's config.plugins. See React Containers > Messaging.
Execute a Command
Inject the CommandBus with useInjection and call execute. It runs the active handler and returns its result as-is, including a Promise if the handler is async. It throws when no handler exists. Use executeAsync when callers should always receive a Promise.
import { CommandBus } from "@wirestate/core";
import { useInjection } from "@wirestate/react";
function AddItemButton({ item }: { item: CartItem }) {
const commandBus = useInjection(CommandBus);
return (
<button
onClick={() => {
const itemCount: number = commandBus.execute("ADD_CART_ITEM", item);
console.info("Cart item count:", itemCount);
}}
>
Add item
</button>
);
}The injected bus is stable while the active container is unchanged, so it is safe to use in a useCallback or effect dependency list.
Execute an Async Command
Use executeAsync when the handler may return a Promise, or when the component should always work in an async way. It always resolves to a Promise.
import { CommandBus } from "@wirestate/core";
import { useInjection } from "@wirestate/react";
import { useCallback, useState } from "react";
function LogoutButton() {
const commandBus = useInjection(CommandBus);
const [pending, setPending] = useState(false);
const logout = useCallback(async () => {
setPending(true);
try {
await commandBus.executeAsync("LOGOUT");
} finally {
setPending(false);
}
}, [commandBus]);
return (
<button disabled={pending} onClick={() => void logout()}>
Log out
</button>
);
}Execute Optional Commands
When a command handler may be absent in some containers, pass a literal { optional: true } so a missing handler returns undefined instead of throwing.
import { CommandBus } from "@wirestate/core";
import { useInjection } from "@wirestate/react";
function DevtoolsButtons() {
const commandBus = useInjection(CommandBus);
return (
<>
<button onClick={() => commandBus.execute("TOGGLE_DEVTOOLS", undefined, { optional: true })}>
Toggle devtools
</button>
<button onClick={() => void commandBus.executeAsync("EXPORT_DEVTOOLS_TRACE", undefined, { optional: true })}>
Export trace
</button>
</>
);
}If the CommandBus itself may be absent (no CommandsPlugin registered), resolve it optionally with useInjection(CommandBus, { optional: true }) and guard before calling.
Handle a Command
import { useOnCommand } from "@wirestate/react";
import { useState } from "react";
function SearchPanel() {
const [open, setOpen] = useState(false);
useOnCommand("OPEN_SEARCH", () => setOpen(true));
return open ? <div>Search</div> : null;
}Handlers unregister when the component unmounts, the command type changes, or the active container changes. The hook keeps the latest handler without re-registering. If several handlers use the same command type, the newest one handles the command.
API Reference
CommandBus, CommandDispatchOptions, useInjection, useOnCommand.