Fix duplicate api requuests for graph fetching
- Optimize graph data fetching conditions - Add isFetching state to prevent duplicate requests - Improve label selection handling
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="./logo.png" />
|
<link rel="icon" type="image/svg+xml" href="./logo.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Lightrag</title>
|
<title>Lightrag</title>
|
||||||
<script type="module" crossorigin src="./assets/index-B9TRs-Wk.js"></script>
|
<script type="module" crossorigin src="./assets/index-fJflQM9b.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-DRGuXfZw.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-DRGuXfZw.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { useLoadGraph, useRegisterEvents, useSetSettings, useSigma } from '@react-sigma/core'
|
import { useLoadGraph, useRegisterEvents, useSetSettings, useSigma } from '@react-sigma/core'
|
||||||
|
import Graph from 'graphology'
|
||||||
// import { useLayoutCircular } from '@react-sigma/layout-circular'
|
// import { useLayoutCircular } from '@react-sigma/layout-circular'
|
||||||
import { useLayoutForceAtlas2 } from '@react-sigma/layout-forceatlas2'
|
import { useLayoutForceAtlas2 } from '@react-sigma/layout-forceatlas2'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
// import useRandomGraph, { EdgeType, NodeType } from '@/hooks/useRandomGraph'
|
// import useRandomGraph, { EdgeType, NodeType } from '@/hooks/useRandomGraph'
|
||||||
import useLightragGraph, { EdgeType, NodeType } from '@/hooks/useLightragGraph'
|
import { EdgeType, NodeType } from '@/hooks/useLightragGraph'
|
||||||
import useTheme from '@/hooks/useTheme'
|
import useTheme from '@/hooks/useTheme'
|
||||||
import * as Constants from '@/lib/constants'
|
import * as Constants from '@/lib/constants'
|
||||||
|
|
||||||
@@ -21,7 +22,6 @@ const isButtonPressed = (ev: MouseEvent | TouchEvent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) => {
|
const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) => {
|
||||||
const { lightrageGraph } = useLightragGraph()
|
|
||||||
const sigma = useSigma<NodeType, EdgeType>()
|
const sigma = useSigma<NodeType, EdgeType>()
|
||||||
const registerEvents = useRegisterEvents<NodeType, EdgeType>()
|
const registerEvents = useRegisterEvents<NodeType, EdgeType>()
|
||||||
const setSettings = useSetSettings<NodeType, EdgeType>()
|
const setSettings = useSetSettings<NodeType, EdgeType>()
|
||||||
@@ -38,17 +38,18 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
|
|||||||
const focusedNode = useGraphStore.use.focusedNode()
|
const focusedNode = useGraphStore.use.focusedNode()
|
||||||
const selectedEdge = useGraphStore.use.selectedEdge()
|
const selectedEdge = useGraphStore.use.selectedEdge()
|
||||||
const focusedEdge = useGraphStore.use.focusedEdge()
|
const focusedEdge = useGraphStore.use.focusedEdge()
|
||||||
|
const sigmaGraph = useGraphStore.use.sigmaGraph()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When component mount or maxIterations changes
|
* When component mount or maxIterations changes
|
||||||
* => load the graph and apply layout
|
* => load the graph and apply layout
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Create & load the graph
|
if (sigmaGraph) {
|
||||||
const graph = lightrageGraph()
|
loadGraph(sigmaGraph as unknown as Graph<NodeType, EdgeType>)
|
||||||
loadGraph(graph)
|
|
||||||
assignLayout()
|
assignLayout()
|
||||||
}, [assignLayout, loadGraph, lightrageGraph, maxIterations])
|
}
|
||||||
|
}, [assignLayout, loadGraph, sigmaGraph, maxIterations])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When component mount
|
* When component mount
|
||||||
|
@@ -57,8 +57,11 @@ const GraphLabels = () => {
|
|||||||
|
|
||||||
const currentLabel = useSettingsStore.getState().queryLabel
|
const currentLabel = useSettingsStore.getState().queryLabel
|
||||||
|
|
||||||
|
if (newLabel === '*' && currentLabel === '*') {
|
||||||
|
// When reselecting '*', just set it again to trigger a new fetch
|
||||||
|
useSettingsStore.getState().setQueryLabel('*')
|
||||||
|
} else if (newLabel === currentLabel && newLabel !== '*') {
|
||||||
// When selecting the same label (except '*'), switch to '*'
|
// When selecting the same label (except '*'), switch to '*'
|
||||||
if (newLabel === currentLabel && newLabel !== '*') {
|
|
||||||
useSettingsStore.getState().setQueryLabel('*')
|
useSettingsStore.getState().setQueryLabel('*')
|
||||||
} else {
|
} else {
|
||||||
useSettingsStore.getState().setQueryLabel(newLabel)
|
useSettingsStore.getState().setQueryLabel(newLabel)
|
||||||
|
@@ -162,13 +162,32 @@ const createSigmaGraph = (rawGraph: RawGraph | null) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const useLightrangeGraph = () => {
|
const useLightrangeGraph = () => {
|
||||||
// Use useRef to maintain lastQueryLabel state between renders
|
|
||||||
const lastQueryLabelRef = useRef({ label: '', maxQueryDepth: 0, minDegree: 0 })
|
|
||||||
const queryLabel = useSettingsStore.use.queryLabel()
|
const queryLabel = useSettingsStore.use.queryLabel()
|
||||||
const rawGraph = useGraphStore.use.rawGraph()
|
const rawGraph = useGraphStore.use.rawGraph()
|
||||||
const sigmaGraph = useGraphStore.use.sigmaGraph()
|
const sigmaGraph = useGraphStore.use.sigmaGraph()
|
||||||
const maxQueryDepth = useSettingsStore.use.graphQueryMaxDepth()
|
const maxQueryDepth = useSettingsStore.use.graphQueryMaxDepth()
|
||||||
const minDegree = useSettingsStore.use.graphMinDegree()
|
const minDegree = useSettingsStore.use.graphMinDegree()
|
||||||
|
const isFetching = useGraphStore.use.isFetching()
|
||||||
|
|
||||||
|
// Use ref to track fetch status
|
||||||
|
const fetchStatusRef = useRef<Record<string, boolean>>({});
|
||||||
|
|
||||||
|
// Track previous parameters to detect actual changes
|
||||||
|
const prevParamsRef = useRef({ queryLabel, maxQueryDepth, minDegree });
|
||||||
|
|
||||||
|
// Reset fetch status only when parameters actually change
|
||||||
|
useEffect(() => {
|
||||||
|
const prevParams = prevParamsRef.current;
|
||||||
|
if (prevParams.queryLabel !== queryLabel ||
|
||||||
|
prevParams.maxQueryDepth !== maxQueryDepth ||
|
||||||
|
prevParams.minDegree !== minDegree) {
|
||||||
|
useGraphStore.getState().setIsFetching(false);
|
||||||
|
// Reset fetch status for new parameters
|
||||||
|
fetchStatusRef.current = {};
|
||||||
|
// Update previous parameters
|
||||||
|
prevParamsRef.current = { queryLabel, maxQueryDepth, minDegree };
|
||||||
|
}
|
||||||
|
}, [queryLabel, maxQueryDepth, minDegree])
|
||||||
|
|
||||||
const getNode = useCallback(
|
const getNode = useCallback(
|
||||||
(nodeId: string) => {
|
(nodeId: string) => {
|
||||||
@@ -186,17 +205,12 @@ const useLightrangeGraph = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (queryLabel) {
|
if (queryLabel) {
|
||||||
// Always fetch data for "*" label
|
const fetchKey = `${queryLabel}-${maxQueryDepth}-${minDegree}`;
|
||||||
// For other labels, only fetch when parameters change
|
|
||||||
const shouldUpdate = true;
|
|
||||||
|
|
||||||
if (shouldUpdate) {
|
|
||||||
lastQueryLabelRef.current = {
|
|
||||||
label: queryLabel,
|
|
||||||
maxQueryDepth,
|
|
||||||
minDegree
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Only fetch if we haven't fetched this combination in the current component lifecycle
|
||||||
|
if (!isFetching && !fetchStatusRef.current[fetchKey]) {
|
||||||
|
useGraphStore.getState().setIsFetching(true);
|
||||||
|
fetchStatusRef.current[fetchKey] = true;
|
||||||
fetchGraph(queryLabel, maxQueryDepth, minDegree).then((data) => {
|
fetchGraph(queryLabel, maxQueryDepth, minDegree).then((data) => {
|
||||||
const state = useGraphStore.getState()
|
const state = useGraphStore.getState()
|
||||||
const newSigmaGraph = createSigmaGraph(data)
|
const newSigmaGraph = createSigmaGraph(data)
|
||||||
@@ -227,6 +241,16 @@ const useLightrangeGraph = () => {
|
|||||||
// Ensure * is there eventhough there is no graph data
|
// Ensure * is there eventhough there is no graph data
|
||||||
state.setGraphLabels(['*']);
|
state.setGraphLabels(['*']);
|
||||||
}
|
}
|
||||||
|
if (!data) {
|
||||||
|
// If data is invalid, remove the fetch flag to allow retry
|
||||||
|
delete fetchStatusRef.current[fetchKey];
|
||||||
|
}
|
||||||
|
// Reset fetching state after all updates are complete
|
||||||
|
state.setIsFetching(false);
|
||||||
|
}).catch(() => {
|
||||||
|
// Reset fetching state and remove flag in case of error
|
||||||
|
useGraphStore.getState().setIsFetching(false);
|
||||||
|
delete fetchStatusRef.current[fetchKey];
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -68,6 +68,7 @@ interface GraphState {
|
|||||||
graphLabels: string[]
|
graphLabels: string[]
|
||||||
|
|
||||||
moveToSelectedNode: boolean
|
moveToSelectedNode: boolean
|
||||||
|
isFetching: boolean
|
||||||
|
|
||||||
setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) => void
|
setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) => void
|
||||||
setFocusedNode: (nodeId: string | null) => void
|
setFocusedNode: (nodeId: string | null) => void
|
||||||
@@ -81,6 +82,7 @@ interface GraphState {
|
|||||||
setRawGraph: (rawGraph: RawGraph | null) => void
|
setRawGraph: (rawGraph: RawGraph | null) => void
|
||||||
setSigmaGraph: (sigmaGraph: DirectedGraph | null) => void
|
setSigmaGraph: (sigmaGraph: DirectedGraph | null) => void
|
||||||
setGraphLabels: (labels: string[]) => void
|
setGraphLabels: (labels: string[]) => void
|
||||||
|
setIsFetching: (isFetching: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const useGraphStoreBase = create<GraphState>()((set) => ({
|
const useGraphStoreBase = create<GraphState>()((set) => ({
|
||||||
@@ -90,11 +92,13 @@ const useGraphStoreBase = create<GraphState>()((set) => ({
|
|||||||
focusedEdge: null,
|
focusedEdge: null,
|
||||||
|
|
||||||
moveToSelectedNode: false,
|
moveToSelectedNode: false,
|
||||||
|
isFetching: false,
|
||||||
|
|
||||||
rawGraph: null,
|
rawGraph: null,
|
||||||
sigmaGraph: null,
|
sigmaGraph: null,
|
||||||
graphLabels: ['*'],
|
graphLabels: ['*'],
|
||||||
|
|
||||||
|
setIsFetching: (isFetching: boolean) => set({ isFetching }),
|
||||||
setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) =>
|
setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) =>
|
||||||
set({ selectedNode: nodeId, moveToSelectedNode }),
|
set({ selectedNode: nodeId, moveToSelectedNode }),
|
||||||
setFocusedNode: (nodeId: string | null) => set({ focusedNode: nodeId }),
|
setFocusedNode: (nodeId: string | null) => set({ focusedNode: nodeId }),
|
||||||
|
Reference in New Issue
Block a user