Skip to content

Commit

Permalink
Merge pull request #228 from mittwald/feature-lazy-dependency
Browse files Browse the repository at this point in the history
feature: support lazy dependencies
  • Loading branch information
JLampeMW authored Jan 23, 2025
2 parents b17a417 + 4708bd3 commit 81320b6
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 10 deletions.
37 changes: 29 additions & 8 deletions packages/models/src/react/provideReact.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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 <span>{model.id}</span>;
};

Expand All @@ -53,10 +63,14 @@ const TestWrapper: FC<PropsWithChildren> = (props) => (
</MittwaldApiModelProvider>
);

const runTest = async (id: number, expectedDataLoadingCount: number) => {
const runTest = async (
id: number,
expectedDataLoadingCount: number,
dynamicId = 0,
) => {
const ui = rerender
? rerender(<TestComponent id={id} />)
: render(<TestComponent id={id} />, {
? rerender(<TestComponent id={id} lazyDependency={dynamicId} />)
: render(<TestComponent id={id} lazyDependency={dynamicId} />, {
wrapper: TestWrapper,
});

Expand All @@ -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
Expand Down
20 changes: 18 additions & 2 deletions packages/models/src/react/provideReact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,30 @@ import { joinedId } from "../lib/joinedId.js";

type AsyncFn = (...args: any[]) => Promise<unknown>;

type ReactProvisionDep = string | number;
type LazyReactProvisionDep = () => ReactProvisionDep;
type ReactProvisionDeps = Array<ReactProvisionDep | LazyReactProvisionDep>;

export const provideReact = <T extends AsyncFn>(
loader: T,
dependencies: string[] = [],
dependencies: ReactProvisionDeps = [],
) => {
type P = Parameters<T>;
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(
Expand Down

0 comments on commit 81320b6

Please sign in to comment.