Skip to content

useUserState

useUserState reads, writes, and drafts user state for the project mounted by SkyStateProvider.

Authentication Setup

User state requires an authenticated end user. Put user-state UI behind an auth gate:

tsx
import { useAuth } from '@skystate/react';

export function UserStateAuthGate({ children }: { children: React.ReactNode }) {
  const auth = useAuth();

  if (auth.status !== 'authenticated') {
    return <button onClick={auth.loginWithRedirect}>Sign in</button>;
  }

  return <>{children}</>;
}

See Auth and subsystem status for the full auth API.


Basic Examples

Read and update a value

tsx
import { useUserState } from '@skystate/react';

export function ThemeToggle() {
  const { value: theme, set: setTheme } = useUserState('theme', 'dark');

  return (
    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
      Theme: {theme}
    </button>
  );
}

Draft a form before saving

tsx
import { useUserState } from '@skystate/react';

export function ProfileEditor() {
  const { draft: profile } = useUserState('profile', { displayName: '' });

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        profile.push();
      }}
    >
      <input
        value={profile.displayValue.displayName}
        onChange={(event) => {
          profile.set((current) => ({
            ...current,
            displayName: event.target.value,
          }));
        }}
      />
      <button type="submit" disabled={!profile.isPending}>Save</button>
      <button type="button" onClick={profile.discard}>Discard</button>
    </form>
  );
}

Show loading and errors

tsx
import { useUserState } from '@skystate/react';

export function UserStateGate({ children }: { children: React.ReactNode }) {
  const userState = useUserState();

  if (userState.status === 'loading') return <Skeleton />;
  if (userState.status === 'error') {
    return <div>{userState.error.message}</div>;
  }

  return <>{children}</>;
}

API

ts
function useUserState(): SubsystemStatus

function useUserState<T = unknown>(
  key: string,
): {
  value: T | null;
  set: (value: T | null | ((prev: T | null) => T | null)) => void;
  draft: UseUserStateDraft<T | null>;
}

function useUserState<T>(
  key: string,
  fallback: T,
): {
  value: T;
  set: (value: T | ((prev: T) => T)) => void;
  draft: UseUserStateDraft<T>;
}

Parameters

ParameterDescription
keyTop-level user-state key such as theme, profile, or preferences.
fallbackValue returned while user state is not ready, when the key is absent, or when the committed value is null. Also narrows value from T | null to T.

Keys are top-level names. They cannot be empty and cannot contain / or ~.

Returns

CallReturn
useUserState(){ status: 'idle' | 'loading' | 'ready' } or { status: 'error'; error: SkyStateError }.
useUserState<T>(key){ value: T | null; set; draft }.
useUserState<T>(key, fallback){ value: T; set; draft }.

set(value)

ts
set(value: T | ((prev: T) => T)): void

Writes a new value for the selected key. The visible value updates immediately; save errors are reported through onError and the no-argument status hook.


Draft Handle

ts
type UseUserStateDraft<T> = {
  displayValue: T;
  pendingValue: T | undefined;
  isPending: boolean;
  set: (value: T | ((displayValue: T) => T)) => void;
  push: () => void;
  discard: () => void;
};
MemberDescription
displayValueDrafted value when present, otherwise the committed value. Safe for controlled inputs.
pendingValueDrafted value, or undefined when untouched.
isPendingWhether a local draft exists.
set(value)Updates the local draft only.
push()Saves the current draft value.
discard()Drops the local draft value.

Public Contract

ContractDetail
Auth requiredUser state reads and writes require a signed-in end user.
Top-level keysKeys are top-level names, not nested paths.
Local updateset updates the visible value immediately.
StatusUse useUserState() with no arguments for loading and error state.
ErrorsValidation, auth, permission, quota, and configuration issues surface through onError and the status hook.
MetadataUse the console, CLI, or REST API for inspection, audit, or history metadata.