mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-09 01:20:09 +00:00
fix: Vue mode socket map data not cleaned up on dynamic input changes (#8469)
## Summary Fixes a bug where socket map data was not properly removed when sockets are dynamically added/removed via DynamicCombo widgets in Vue mode (Nodes 2.0). ## Problem When DynamicCombo widgets (e.g., `should_remesh` on Meshy nodes) change their selection, inputs are dynamically added/removed. The Vue `v-for` loop in `NodeSlots.vue` was using array index as the `:key`, causing Vue to **reuse** slot components instead of properly unmounting them. This led to: - Socket map entries leaking (never cleaned up) - Socket positions becoming desynced - Stale cached offset data ## Solution 1. **Use slot `name` as Vue key** instead of array index in `NodeSlots.vue` - Slot names are unique per node (enforced by ComfyUI backend) - When a slot is removed, Vue sees the key disappear and properly unmounts the component - `onUnmounted` cleanup in `useSlotElementTracking` now runs correctly 2. **Add defensive cleanup** in `useSlotElementTracking.ts` - Before registering a new slot, check if a stale entry exists with the same key - Clean up stale entry to handle any edge cases ## Related - Fixes COM-12970 - Related to #7837 (fixed LiteGraph version of this bug, but not Vue mode) ## Testing - Quality checks pass (typecheck, lint, format) - Manual testing with DynamicCombo nodes (Meshy, nodes_logic) recommended ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8469-fix-Vue-mode-socket-map-data-not-cleaned-up-on-dynamic-input-changes-2f86d73d365081e599eadca4f15e6b6e) by [Unito](https://www.unito.io) --------- Co-authored-by: Subagent 5 <subagent@example.com> Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
>
|
||||
<InputSlot
|
||||
v-for="(input, index) in filteredInputs"
|
||||
:key="`input-${index}`"
|
||||
:key="`input-${input.name}`"
|
||||
:slot-data="input"
|
||||
:node-type="nodeData?.type || ''"
|
||||
:node-id="nodeData?.id != null ? String(nodeData.id) : ''"
|
||||
@@ -23,7 +23,7 @@
|
||||
>
|
||||
<OutputSlot
|
||||
v-for="(output, index) in nodeData.outputs"
|
||||
:key="`output-${index}`"
|
||||
:key="`output-${output.name}`"
|
||||
:slot-data="output"
|
||||
:node-type="nodeData?.type || ''"
|
||||
:node-id="nodeData?.id != null ? String(nodeData.id) : ''"
|
||||
|
||||
@@ -183,6 +183,14 @@ export function useSlotElementTracking(options: {
|
||||
// Register slot
|
||||
const slotKey = getSlotKey(nodeId, index, type === 'input')
|
||||
|
||||
// Defensive cleanup: remove stale entry if it exists with different element
|
||||
// This handles edge cases where Vue component reuse prevents proper unmount
|
||||
const existingEntry = node.slots.get(slotKey)
|
||||
if (existingEntry && existingEntry.el !== el) {
|
||||
delete existingEntry.el.dataset.slotKey
|
||||
layoutStore.deleteSlotLayout(slotKey)
|
||||
}
|
||||
|
||||
el.dataset.slotKey = slotKey
|
||||
node.slots.set(slotKey, { el, index, type })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user