Skip to content

Commit 6820633

Browse files
authored
fix: preserve Vue node reactivity during undo/redo operations (#7222)
## Summary preserve Vue node reactivity during undo/redo operations Root Cause: The Vue reactivity chain was broken during undo/redo operations: 1. handleDeleteNode was deleting nodeRefs and nodeTriggers 2. Vue components still held references to the old refs 3. When nodes were recreated, finalizeOperation tried to call triggers but they were already deleted 4. Vue didn't know the data had changed, so nodes didn't visually update fix #7040 ## Screenshots https://github.com/user-attachments/assets/2feb294a-36e8-4bbe-b3f7-b7015066abc5 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7222-fix-preserve-Vue-node-reactivity-during-undo-redo-operations-2c36d73d3650819ab72afb10cbdaf39a) by [Unito](https://www.unito.io)
1 parent 8c5584c commit 6820633

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

src/renderer/core/layout/store/layoutStore.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,15 @@ class LayoutStoreImpl implements LayoutStore {
956956
return this.currentActor
957957
}
958958

959+
/**
960+
* Clean up refs and triggers for a node when its Vue component unmounts.
961+
* This should be called from the component's onUnmounted hook.
962+
*/
963+
cleanupNodeRef(nodeId: NodeId): void {
964+
this.nodeRefs.delete(nodeId)
965+
this.nodeTriggers.delete(nodeId)
966+
}
967+
959968
/**
960969
* Initialize store with existing nodes
961970
*/
@@ -964,8 +973,10 @@ class LayoutStoreImpl implements LayoutStore {
964973
): void {
965974
this.ydoc.transact(() => {
966975
this.ynodes.clear()
967-
this.nodeRefs.clear()
968-
this.nodeTriggers.clear()
976+
// Note: We intentionally do NOT clear nodeRefs and nodeTriggers here.
977+
// Vue components may already hold references to these refs, and clearing
978+
// them would break the reactivity chain. The refs will be reused when
979+
// nodes are recreated, and stale refs will be cleaned up over time.
969980
this.spatialIndex.clear()
970981
this.linkSegmentSpatialIndex.clear()
971982
this.slotSpatialIndex.clear()
@@ -995,6 +1006,9 @@ class LayoutStoreImpl implements LayoutStore {
9951006
// Add to spatial index
9961007
this.spatialIndex.insert(layout.id, layout.bounds)
9971008
})
1009+
1010+
// Trigger all existing refs to notify Vue of the new data
1011+
this.nodeTriggers.forEach((trigger) => trigger())
9981012
}, 'initialization')
9991013
}
10001014

@@ -1085,8 +1099,10 @@ class LayoutStoreImpl implements LayoutStore {
10851099
if (!this.ynodes.has(operation.nodeId)) return
10861100

10871101
this.ynodes.delete(operation.nodeId)
1088-
this.nodeRefs.delete(operation.nodeId)
1089-
this.nodeTriggers.delete(operation.nodeId)
1102+
// Note: We intentionally do NOT delete nodeRefs and nodeTriggers here.
1103+
// During undo/redo, Vue components may still hold references to the old ref.
1104+
// If we delete the trigger, Vue won't be notified when the node is re-created.
1105+
// The trigger will be called in finalizeOperation to notify Vue of the change.
10901106

10911107
// Remove from spatial index
10921108
this.spatialIndex.remove(operation.nodeId)

src/renderer/extensions/vueNodes/layout/useNodeLayout.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { computed, toValue } from 'vue'
1+
import { computed, onUnmounted, toValue } from 'vue'
22
import type { MaybeRefOrGetter } from 'vue'
33

44
import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations'
@@ -17,6 +17,11 @@ export function useNodeLayout(nodeIdMaybe: MaybeRefOrGetter<string>) {
1717
// Get the customRef for this node (shared write access)
1818
const layoutRef = layoutStore.getNodeLayoutRef(nodeId)
1919

20+
// Clean up refs and triggers when Vue component unmounts
21+
onUnmounted(() => {
22+
layoutStore.cleanupNodeRef(nodeId)
23+
})
24+
2025
// Computed properties for easy access
2126
const position = computed(() => {
2227
const layout = layoutRef.value

0 commit comments

Comments
 (0)