Skip to content

[Bug] GeneralSection handleNotificationToggle fires IPC call inside setState updater #400

@samzong

Description

@samzong

Problem

GeneralSection.handleNotificationToggle performs an IPC side-effect inside a setState updater. React explicitly disallows this — state updaters must be pure functions. In React Strict Mode (enabled in dev), updaters are invoked twice to detect impurity, which means window.clawwork.updateSettings(...) fires twice for every notification toggle, persisting the same change twice and doubling the IPC round-trip cost.

Location

File: packages/desktop/src/renderer/layouts/Settings/sections/GeneralSection.tsx:102-111

const handleNotificationToggle = useCallback(
  (key: 'taskComplete' | 'approvalRequest' | 'gatewayDisconnect', value: boolean) => {
    setNotifyState((prev) => {
      const next = { ...prev, [key]: value };
      window.clawwork.updateSettings({ notifications: next });  // ← side effect in updater
      return next;
    });
  },
  [],
);

Fix Approach

Compute the new state outside the updater, then dispatch both the state update and the IPC call as separate effects:

const handleNotificationToggle = useCallback(
  (key: 'taskComplete' | 'approvalRequest' | 'gatewayDisconnect', value: boolean) => {
    const next = { ...notifyState, [key]: value };
    setNotifyState(next);
    window.clawwork.updateSettings({ notifications: next });
  },
  [notifyState],
);

Or, if you want to avoid re-creating the callback on every state change, keep a ref that tracks the latest notifyState and use it inside the callback.

Verification

  1. Run pnpm check — must pass.
  2. Manual: in dev mode (Strict Mode enabled), toggle a notification switch and confirm only a single IPC call fires in the main-process logs.

Context

  • WG: UI & Design System
  • Priority: Low (good first issue)
  • Estimated effort: 10-15 minutes

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/uiUI & Design System WGgood first issueGood for newcomerskind/bugCategorizes issue or PR as related to a bug

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions