@fcannizzaro/streamdeck-react

Settings Hooks

Bi-directional settings sync between React state and the Stream Deck SDK.

useSettings

Returns a [settings, setSettings] tuple with shallow-merge semantics. Changes are synced bidirectionally between the React tree and the Stream Deck SDK.

function useSettings<S extends JsonObject = JsonObject>(): [S, (partial: Partial<S>) => void];

Merge Semantics

setSettings does a shallow merge ({ ...current, ...partial }), matching the Stream Deck SDK's setSettings behavior. This is intentionally different from React's useState -- it always merges, never replaces.

Example

type MySettings = { color: string; brightness: number };

function MyKey() {
  const [settings, setSettings] = useSettings<MySettings>();

  useKeyDown(() => {
    setSettings({ brightness: Math.min(100, settings.brightness + 10) });
  });

  return (
    <div style={{
      width: '100%', height: '100%',
      background: settings.color,
      opacity: settings.brightness / 100,
      alignItems: 'center', justifyContent: 'center',
    }}>
      <span style={{ color: 'white', fontSize: 20 }}>{settings.brightness}%</span>
    </div>
  );
}

Sync Flow

  1. React to SDK: calling setSettings({ count: 5 }) updates the internal React state (triggers re-render) and calls action.setSettings() on the SDK to persist.
  2. SDK to React: when the Property Inspector saves settings (triggering onDidReceiveSettings), the internal state updates and components using useSettings() re-render.
  3. Conflict resolution: the SDK is the source of truth. Last write wins.

useGlobalSettings

Same pattern as useSettings, but for plugin-wide global settings shared across all action instances.

function useGlobalSettings<G extends JsonObject = JsonObject>(): [G, (partial: Partial<G>) => void];
type GlobalConfig = { apiKey: string; theme: 'light' | 'dark' };

function MyKey() {
  const [global] = useGlobalSettings<GlobalConfig>();

  return (
    <div style={{
      width: '100%', height: '100%',
      background: global.theme === 'dark' ? '#000' : '#fff',
      alignItems: 'center', justifyContent: 'center',
    }}>
      <span style={{ color: global.theme === 'dark' ? '#fff' : '#000', fontSize: 14 }}>
        {global.apiKey ? 'Connected' : 'No API Key'}
      </span>
    </div>
  );
}

See also Settings & Property Inspector for the full sync architecture.

On this page