Fix broadcast no-op: stop depending on orch object in LeafPane effects
The bug: clicking 📡 made the visual update (orange border) but typing
in a broadcasting pane only wrote to that pane — peers never received
the keystrokes.
Root cause: the orch context value (useMemo'd over activeLeafId,
distros, and the operation callbacks) is recreated every time
activeLeafId changes (i.e. every click). useEffect cleanups in
LeafPane that had `orch` in their deps fired their cleanup-then-setup
cycle on every click. The unmount-cleanup for paneId registration
ran `orch.registerPaneId(leaf.id, null)`, silently deleting paneIds
from App's paneIdByLeafRef map — so when broadcastFrom later walked
the tree looking up peers, the map returned undefined for every leaf
and the actual writeToPane calls never happened.
Fix: depend on the specific stable method references
(`orch.registerPaneId`, `orch.notify`, etc.) instead of the orch
object itself. The methods are all useCallback'd with stable deps
in App.tsx, so their references don't change across orch object
recreations — effect deps stay stable, no spurious cleanup.
Applied the same fix to all orch-using effects/callbacks in
LeafPane (commitLabel, pickDistro, onPaneClick, onPaneSpawned,
onXtermFocus, onTerminalInput, idle interval, paneId cleanup).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c8234442f1
commit
2a0c096095
1 changed files with 18 additions and 9 deletions
|
|
@ -41,7 +41,7 @@ export default function LeafPane({ leaf }: { leaf: LeafNode }) {
|
|||
if (!editingLabel) return;
|
||||
orch.setLabel(leaf.id, labelDraft);
|
||||
setEditingLabel(false);
|
||||
}, [editingLabel, orch, leaf.id, labelDraft]);
|
||||
}, [editingLabel, orch.setLabel, leaf.id, labelDraft]);
|
||||
const cancelLabel = useCallback(() => setEditingLabel(false), []);
|
||||
const onLabelKey = useCallback(
|
||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||
|
|
@ -67,7 +67,7 @@ export default function LeafPane({ leaf }: { leaf: LeafNode }) {
|
|||
setDistroOpen(false);
|
||||
if (d !== leaf.distro) orch.setDistro(leaf.id, d);
|
||||
},
|
||||
[orch, leaf.id, leaf.distro],
|
||||
[orch.setDistro, leaf.id, leaf.distro],
|
||||
);
|
||||
// Dismiss popover on outside click
|
||||
useEffect(() => {
|
||||
|
|
@ -95,14 +95,17 @@ export default function LeafPane({ leaf }: { leaf: LeafNode }) {
|
|||
}
|
||||
}, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, [leaf.label, leaf.distro, orch]);
|
||||
// Depend on the stable notify function, not the whole orch object.
|
||||
// orch is recreated every time activeLeafId/distros change; depending
|
||||
// on it would tear down and rebuild this interval on every click.
|
||||
}, [leaf.label, leaf.distro, orch.notify]);
|
||||
|
||||
// ---- broadcast ---------------------------------------------------------
|
||||
const onTerminalInput = useCallback(
|
||||
(b64: string) => {
|
||||
if (isBroadcasting) orch.broadcastFrom(leaf.id, b64);
|
||||
},
|
||||
[isBroadcasting, orch, leaf.id],
|
||||
[isBroadcasting, orch.broadcastFrom, leaf.id],
|
||||
);
|
||||
|
||||
// ---- focus / active highlighting ---------------------------------------
|
||||
|
|
@ -114,20 +117,26 @@ export default function LeafPane({ leaf }: { leaf: LeafNode }) {
|
|||
|
||||
const onPaneClick = useCallback(() => {
|
||||
orch.setActive(leaf.id);
|
||||
}, [orch, leaf.id]);
|
||||
}, [orch.setActive, leaf.id]);
|
||||
|
||||
const onPaneSpawned = useCallback(
|
||||
(paneId: number) => {
|
||||
orch.registerPaneId(leaf.id, paneId);
|
||||
},
|
||||
[orch, leaf.id],
|
||||
[orch.registerPaneId, leaf.id],
|
||||
);
|
||||
// Unregister on unmount
|
||||
// Unregister on TRUE unmount only — depending on `orch` here would
|
||||
// delete the paneId from App's lookup on every activeLeafId change,
|
||||
// which broke broadcast routing (peers found, but their paneIds
|
||||
// had been silently removed from the map).
|
||||
useEffect(() => {
|
||||
return () => orch.registerPaneId(leaf.id, null);
|
||||
}, [orch, leaf.id]);
|
||||
}, [orch.registerPaneId, leaf.id]);
|
||||
|
||||
const onXtermFocus = useCallback(() => orch.setActive(leaf.id), [orch, leaf.id]);
|
||||
const onXtermFocus = useCallback(
|
||||
() => orch.setActive(leaf.id),
|
||||
[orch.setActive, leaf.id],
|
||||
);
|
||||
|
||||
const onStatus = useCallback((msg: string, ok: boolean) => {
|
||||
setStatus(msg);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue