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
- Run
pnpm check — must pass.
- 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
Problem
GeneralSection.handleNotificationToggleperforms an IPC side-effect inside asetStateupdater. 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 meanswindow.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-111Fix Approach
Compute the new state outside the updater, then dispatch both the state update and the IPC call as separate effects:
Or, if you want to avoid re-creating the callback on every state change, keep a ref that tracks the latest
notifyStateand use it inside the callback.Verification
pnpm check— must pass.Context