clawwork-ai/ClawWork

[Bug] GeneralSection handleNotificationToggle fires IPC call inside setState updater

Open

#400 opened on Apr 15, 2026

View on GitHub
 (1 comment) (0 reactions) (0 assignees)TypeScript (63 forks)github user discovery
area/uigood first issuekind/bug

Repository metrics

Stars
 (519 stars)
PR merge metrics
 (PR metrics pending)

Description

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

Contributor guide