diff --git a/packages/models/src/react/provideReact.test.tsx b/packages/models/src/react/provideReact.test.tsx
index 5df42fca..0bb22874 100644
--- a/packages/models/src/react/provideReact.test.tsx
+++ b/packages/models/src/react/provideReact.test.tsx
@@ -28,8 +28,15 @@ beforeEach(() => {
});
class TestModel extends ReferenceModel {
- public static ofId(id: number) {
- return new TestModel(String(id));
+ public readonly lazyDependency: number;
+
+ public static ofId(id: number, lazyDependency = 0) {
+ return new TestModel(String(id), lazyDependency);
+ }
+
+ public constructor(id: string, lazyDependency: number) {
+ super(id);
+ this.lazyDependency = lazyDependency;
}
public getDetailed = provideReact(async () => {
@@ -39,11 +46,14 @@ class TestModel extends ReferenceModel {
id: this.id,
foo: true,
};
- }, [this.id]);
+ }, [this.id, () => this.lazyDependency]);
}
-const TestComponent: FC<{ id: number }> = (props) => {
- const model = TestModel.ofId(props.id).getDetailed.use();
+const TestComponent: FC<{ id: number; lazyDependency?: number }> = (props) => {
+ const model = TestModel.ofId(
+ props.id,
+ props.lazyDependency,
+ ).getDetailed.use();
return {model.id};
};
@@ -53,10 +63,14 @@ const TestWrapper: FC = (props) => (
);
-const runTest = async (id: number, expectedDataLoadingCount: number) => {
+const runTest = async (
+ id: number,
+ expectedDataLoadingCount: number,
+ dynamicId = 0,
+) => {
const ui = rerender
- ? rerender()
- : render(, {
+ ? rerender()
+ : render(, {
wrapper: TestWrapper,
});
@@ -79,6 +93,13 @@ test("Model caches data", async () => {
await runTest(43, 2);
});
+test("Model caches data with lazy dependency", async () => {
+ await runTest(43, 1);
+ await runTest(43, 2, 42);
+ await runTest(43, 2, 42);
+ await runTest(43, 3, 43);
+});
+
test("Model cache can be refreshed", async () => {
await runTest(42, 1);
// Tag does not exist
diff --git a/packages/models/src/react/provideReact.ts b/packages/models/src/react/provideReact.ts
index cb3f4d2a..31f6be85 100644
--- a/packages/models/src/react/provideReact.ts
+++ b/packages/models/src/react/provideReact.ts
@@ -6,14 +6,30 @@ import { joinedId } from "../lib/joinedId.js";
type AsyncFn = (...args: any[]) => Promise;
+type ReactProvisionDep = string | number;
+type LazyReactProvisionDep = () => ReactProvisionDep;
+type ReactProvisionDeps = Array;
+
export const provideReact = (
loader: T,
- dependencies: string[] = [],
+ dependencies: ReactProvisionDeps = [],
) => {
type P = Parameters;
- const provisionId = joinedId(hash(loader), ...dependencies);
+ const loaderHash = hash(loader);
+ let cachedProvisionId: string | undefined;
const getAsyncResource = (params: P) => {
+ const provisionId =
+ cachedProvisionId ??
+ joinedId(
+ loaderHash,
+ ...dependencies
+ .map((d) => (typeof d === "function" ? d() : d))
+ .map((d) => hash(d)),
+ );
+
+ cachedProvisionId = provisionId;
+
const contextId = joinedId(provisionId, hash(params));
const loaderWithContext = reactProvisionContext.bind(