mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
When switching from graph view to skill view during an active preview run, SSE callbacks continue executing and attempt to update ReactFlow node/edge states. This could cause errors since the component is unmounted. Add optional `isMountedRef` parameter to `useNodesInteractionsWithoutSync` and `useEdgesInteractionsWithoutSync` hooks. When provided, operations are skipped if the component has unmounted, preventing potential errors while allowing the SSE connection to continue running in the background. BREAKING CHANGE: `useNodesInteractionsWithoutSync` and `useEdgesInteractionsWithoutSync` now accept an optional `isMountedRef` parameter. Existing callers are unaffected as the parameter is optional.
73 lines
1.9 KiB
TypeScript
73 lines
1.9 KiB
TypeScript
import type { RefObject } from 'react'
|
|
import { produce } from 'immer'
|
|
import { useCallback } from 'react'
|
|
import { useStoreApi } from 'reactflow'
|
|
import { NodeRunningStatus } from '../types'
|
|
|
|
export const useNodesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean>) => {
|
|
const store = useStoreApi()
|
|
|
|
const handleNodeCancelRunningStatus = useCallback(() => {
|
|
if (isMountedRef && isMountedRef.current === false)
|
|
return
|
|
|
|
const {
|
|
getNodes,
|
|
setNodes,
|
|
} = store.getState()
|
|
|
|
const nodes = getNodes()
|
|
const newNodes = produce(nodes, (draft) => {
|
|
draft.forEach((node) => {
|
|
node.data._runningStatus = undefined
|
|
node.data._waitingRun = false
|
|
})
|
|
})
|
|
setNodes(newNodes)
|
|
}, [store, isMountedRef])
|
|
|
|
const handleCancelAllNodeSuccessStatus = useCallback(() => {
|
|
if (isMountedRef && isMountedRef.current === false)
|
|
return
|
|
|
|
const {
|
|
getNodes,
|
|
setNodes,
|
|
} = store.getState()
|
|
|
|
const nodes = getNodes()
|
|
const newNodes = produce(nodes, (draft) => {
|
|
draft.forEach((node) => {
|
|
if (node.data._runningStatus === NodeRunningStatus.Succeeded)
|
|
node.data._runningStatus = undefined
|
|
})
|
|
})
|
|
setNodes(newNodes)
|
|
}, [store, isMountedRef])
|
|
|
|
const handleCancelNodeSuccessStatus = useCallback((nodeId: string) => {
|
|
if (isMountedRef && isMountedRef.current === false)
|
|
return
|
|
|
|
const {
|
|
getNodes,
|
|
setNodes,
|
|
} = store.getState()
|
|
|
|
const newNodes = produce(getNodes(), (draft) => {
|
|
const node = draft.find(n => n.id === nodeId)
|
|
if (node && node.data._runningStatus === NodeRunningStatus.Succeeded) {
|
|
node.data._runningStatus = undefined
|
|
node.data._waitingRun = false
|
|
}
|
|
})
|
|
setNodes(newNodes)
|
|
}, [store, isMountedRef])
|
|
|
|
return {
|
|
handleNodeCancelRunningStatus,
|
|
handleCancelAllNodeSuccessStatus,
|
|
handleCancelNodeSuccessStatus,
|
|
}
|
|
}
|