React

Hook-based wrappers using useState / useEffect. Input is a plain value (not a getter) — dependencies tracked via JSON.stringify.

Setup

toml
# metaxy.config.toml
[output]
react = "src/lib/rpc.react.ts"

or via CLI

sh
metaxy generate --react-output src/lib/rpc.react.ts

useQuery

ts
import { useQuery } from './rpc.react';
import { rpc } from './client';

function UserList() {
  const [page, setPage] = useState(1);

  // Refetches when page changes
  const users = useQuery(rpc, 'list_users', page, {
    enabled: page > 0,
    refetchInterval: 30000,
    onSuccess: (data) => console.log(data),
  });

  // Void input
  const time = useQuery(rpc, 'time');

  return (
    <>
      {users.isLoading && <p>Loading...</p>}
      {users.data?.map(u => <div key={u.id}>{u.name}</div>)}
      <button onClick={() => users.refetch()}>Refresh</button>
    </>
  );
}

useMutation

ts
import { useMutation } from './rpc.react';

function CreateForm() {
  const create = useMutation(rpc, 'create_user', {
    onSuccess: (data) => console.log('Created:', data),
    onError: (err) => console.error(err),
  });

  // Await the result
  const handleSubmit = async () => {
    try {
      const user = await create.mutateAsync({ name: 'Alice' });
      console.log('Created:', user);
    } catch (err) {
      // err is RpcError
    }
  };

  return (
    <>
      <button onClick={handleSubmit} disabled={create.isLoading}>
        {create.isLoading ? 'Creating...' : 'Create'}
      </button>
      {create.isError && <p>Error: {create.error?.message}</p>}
      {create.isSuccess && <p>Created: {create.data?.name}</p>}
    </>
  );
}

visit GitHub to learn more about metaxy