diff --git a/src/frontend/src/contexts/typesContext.tsx b/src/frontend/src/contexts/typesContext.tsx index 000bfa472..f0f765bb6 100644 --- a/src/frontend/src/contexts/typesContext.tsx +++ b/src/frontend/src/contexts/typesContext.tsx @@ -27,37 +27,71 @@ export function TypesProvider({ children }: { children: ReactNode }) { const [data, setData] = useState({}); useEffect(() => { - async function getTypes(): Promise { - // Make an asynchronous API call to retrieve all data. - let result = await getAll(); + let delay = 1000; // Start delay of 1 second + let intervalId = null; + let retryCount = 0; // Count of retry attempts + const maxRetryCount = 5; // Max retry attempts - // Update the state of the component with the retrieved data. - setData(result.data); - setTemplates( - Object.keys(result.data).reduce((acc, curr) => { - Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { - acc[c] = result.data[curr][c]; - }); - return acc; - }, {}) - ); - // Set the types by reducing over the keys of the result data and updating the accumulator. - setTypes( - Object.keys(result.data).reduce((acc, curr) => { - Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { - acc[c] = curr; - // Add the base classes to the accumulator as well. - result.data[curr][c].base_classes?.forEach((b) => { - acc[b] = curr; - }); - }); - return acc; - }, {}) - ); + // We will keep a flag to handle the case where the component is unmounted before the API call resolves. + let isMounted = true; + + async function getTypes(): Promise { + try { + const result = await getAll(); + // Make sure to only update the state if the component is still mounted. + if (isMounted) { + // Continue with your logic... + setData(result.data); + setTemplates( + Object.keys(result.data).reduce((acc, curr) => { + Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { + acc[c] = result.data[curr][c]; + }); + return acc; + }, {}) + ); + // Set the types by reducing over the keys of the result data and updating the accumulator. + setTypes( + Object.keys(result.data).reduce((acc, curr) => { + Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { + acc[c] = curr; + // Add the base classes to the accumulator as well. + result.data[curr][c].base_classes?.forEach((b) => { + acc[b] = curr; + }); + }); + return acc; + }, {}) + ); + } + // Clear the interval if successful. + clearInterval(intervalId); + } catch (error) { + retryCount++; + // On error, double the delay for the next attempt up to a maximum. + delay = Math.min(30000, delay * 2); + // Log errors but don't do anything else - the function will try again on the next interval. + console.error(error); + // Clear the old interval and start a new one with the new delay. + if (retryCount <= maxRetryCount) { + clearInterval(intervalId); + intervalId = setInterval(getTypes, delay); + } else { + console.error("Max retry attempts reached. Stopping retries."); + } + } } - // Call the getTypes function. - getTypes(); - }, [setTypes]); + + // Start the initial interval. + intervalId = setInterval(getTypes, delay); + + return () => { + // This will clear the interval when the component unmounts, or when the dependencies of the useEffect hook change. + clearInterval(intervalId); + // Indicate that the component has been unmounted. + isMounted = false; + }; + }, []); function deleteNode(idx: string) { reactFlowInstance.setNodes(