Skip to content

Commit e213be4

Browse files
authored
Cache componentdigest get (#1018)
### TL;DR Export the QueryClient instance and pass it to the PublishedComponentsLibrary to enable component caching. ### What changed? - Exported the QueryClient instance from index.tsx to make it accessible throughout the application - Modified the PublishedComponentsLibrary to accept a QueryClient in its constructor - Updated the ComponentLibraryProvider to: - Use the QueryClient via useQueryClient hook - Create the componentLibraries map in a useMemo hook - Move the getComponentLibraryObject function inside the component and wrap it in useCallback - Added caching for component digest fetching with a 24-hour stale time ### How to test? 1. Verify that the application loads correctly with the exported QueryClient 2. Test component loading from the published components library 3. Verify that subsequent requests for the same component digest use the cached data 4. Check that the component library provider correctly initializes with the query client ### Why make this change? This change improves performance by caching component digest data for 24 hours, reducing redundant API calls when the same components are accessed multiple times. By injecting the QueryClient into the PublishedComponentsLibrary, we enable proper data caching and reuse across the application, which leads to a more responsive user experience and reduced server load.
1 parent d7980ea commit e213be4

File tree

4 files changed

+62
-20
lines changed

4 files changed

+62
-20
lines changed

src/providers/ComponentLibraryProvider/ComponentLibraryProvider.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useQuery } from "@tanstack/react-query";
1+
import { useQuery, useQueryClient } from "@tanstack/react-query";
22
import {
33
type ReactNode,
44
useCallback,
@@ -89,25 +89,33 @@ const ComponentLibraryContext =
8989
"ComponentLibraryProvider",
9090
);
9191

92-
const componentLibraries = new Map<AvailableComponentLibraries, Library>([
93-
["published_components", new PublishedComponentsLibrary()],
94-
]);
95-
96-
function getComponentLibraryObject(libraryName: AvailableComponentLibraries) {
97-
if (!componentLibraries.has(libraryName)) {
98-
throw new Error(`Component library "${libraryName}" is not supported.`);
99-
}
100-
101-
return componentLibraries.get(libraryName) as Library;
102-
}
103-
10492
export const ComponentLibraryProvider = ({
10593
children,
10694
}: {
10795
children: ReactNode;
10896
}) => {
10997
const { graphSpec } = useComponentSpec();
11098
const { currentSearchFilter } = useForcedSearchContext();
99+
const queryClient = useQueryClient();
100+
101+
const componentLibraries = useMemo(
102+
() =>
103+
new Map<AvailableComponentLibraries, Library>([
104+
["published_components", new PublishedComponentsLibrary(queryClient)],
105+
]),
106+
[queryClient],
107+
);
108+
109+
const getComponentLibraryObject = useCallback(
110+
(libraryName: AvailableComponentLibraries) => {
111+
if (!componentLibraries.has(libraryName)) {
112+
throw new Error(`Component library "${libraryName}" is not supported.`);
113+
}
114+
115+
return componentLibraries.get(libraryName) as Library;
116+
},
117+
[componentLibraries],
118+
);
111119

112120
const [componentLibrary, setComponentLibrary] = useState<ComponentLibrary>();
113121
const [userComponentsFolder, setUserComponentsFolder] =

src/providers/ComponentLibraryProvider/libraries/publishedComponentsLibrary.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { QueryClient } from "@tanstack/react-query";
12
import yaml from "js-yaml";
23
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
34

@@ -108,9 +109,33 @@ describe("PublishedComponentsLibrary", () => {
108109
});
109110

110111
let library: PublishedComponentsLibrary;
112+
let mockQueryClient: QueryClient;
111113

112114
beforeEach(() => {
113-
library = new PublishedComponentsLibrary();
115+
mockQueryClient = new QueryClient({
116+
defaultOptions: {
117+
queries: { retry: false },
118+
mutations: { retry: false },
119+
},
120+
});
121+
122+
// Mock the fetchQuery method
123+
vi.spyOn(mockQueryClient, "fetchQuery").mockImplementation(
124+
async ({ queryFn, queryKey }) => {
125+
return typeof queryFn === "function"
126+
? await queryFn({
127+
queryKey,
128+
signal: new AbortController().signal,
129+
client: mockQueryClient,
130+
pageParam: undefined,
131+
direction: "forward" as const,
132+
meta: undefined,
133+
})
134+
: undefined;
135+
},
136+
);
137+
138+
library = new PublishedComponentsLibrary(mockQueryClient);
114139
vi.clearAllMocks();
115140

116141
// Default fetch mock

src/providers/ComponentLibraryProvider/libraries/publishedComponentsLibrary.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { QueryClient } from "@tanstack/react-query";
2+
13
import {
24
getApiComponentsDigestGet,
35
listApiPublishedComponentsGet,
@@ -16,7 +18,7 @@ import {
1618
isDiscoverableComponentReference,
1719
} from "@/utils/componentSpec";
1820
import type { ComponentReferenceWithSpec } from "@/utils/componentStore";
19-
import { API_URL } from "@/utils/constants";
21+
import { API_URL, TWENTY_FOUR_HOURS_IN_MS } from "@/utils/constants";
2022

2123
import { isValidFilterRequest, type LibraryFilterRequest } from "../types";
2224
import {
@@ -57,8 +59,10 @@ class BackendLibraryError extends Error {
5759

5860
export class PublishedComponentsLibrary implements Library {
5961
#knownDigests: Set<string> = new Set();
62+
#queryClient: QueryClient;
6063

61-
constructor() {
64+
constructor(queryClient: QueryClient) {
65+
this.#queryClient = queryClient;
6266
// load known digests from storage
6367
// todo: prefetch components?
6468
}
@@ -75,10 +79,13 @@ export class PublishedComponentsLibrary implements Library {
7579
return true;
7680
}
7781

78-
const getComponentResult = await getApiComponentsDigestGet({
79-
path: {
80-
digest: component.digest,
81-
},
82+
const getComponentResult = await this.#queryClient.fetchQuery({
83+
queryKey: ["componentDigest", component.digest],
84+
queryFn: () =>
85+
getApiComponentsDigestGet({
86+
path: { digest: component.digest },
87+
}),
88+
staleTime: TWENTY_FOUR_HOURS_IN_MS,
8289
});
8390

8491
if (getComponentResult.response.status !== 200) {

src/utils/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,5 @@ export const KEYBOARD_SHORTCUTS = {
7373

7474
// Container exit codes
7575
export const EXIT_CODE_OOM = 137; // SIGKILL (128 + 9) - Out of Memory
76+
77+
export const TWENTY_FOUR_HOURS_IN_MS = 24 * 60 * 60 * 1000;

0 commit comments

Comments
 (0)