Skip to content

Commit

Permalink
Refetch when provider props change
Browse files Browse the repository at this point in the history
  • Loading branch information
seanlaff committed Jun 22, 2020
1 parent 82b6d98 commit c5c0fe0
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 5 deletions.
116 changes: 115 additions & 1 deletion src/Get.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,121 @@ describe("Get", () => {
});
});

describe("refetch after update", () => {
describe("refetch after provider props update", () => {
it("should refetch when base changes", async () => {
const firstAPI = nock("https://my-awesome-api.fake")
.get("/")
.reply(200, { id: 1 });

const secondAPI = nock("https://my-new-api.fake")
.get("/")
.reply(200, { id: 2 });

const children = jest.fn();
children.mockReturnValue(<div />);

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake">
<Get path="">{children}</Get>
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-new-api.fake">
<Get path="">{children}</Get>
</RestfulProvider>,
);

await wait(() => expect(firstAPI.isDone()).toBeTruthy());
await wait(() => expect(secondAPI.isDone()).toBeTruthy());
});
it("should refetch when parentPath changes", async () => {
const firstAPI = nock("https://my-awesome-api.fake")
.get("/parent1")
.reply(200, { id: 1 });

const secondAPI = nock("https://my-awesome-api.fake")
.get("/parent2")
.reply(200, { id: 2 });

const children = jest.fn();
children.mockReturnValue(<div />);

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake" parentPath="/parent1">
<Get path="">{children}</Get>
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-awesome-api.fake" parentPath="/parent2">
<Get path="">{children}</Get>
</RestfulProvider>,
);

await wait(() => expect(firstAPI.isDone()).toBeTruthy());
await wait(() => expect(secondAPI.isDone()).toBeTruthy());
});
it("should refetch when queryParams change", async () => {
const firstAPI = nock("https://my-awesome-api.fake")
.get("/")
.reply(200, { id: 1 })
.persist();
const secondAPI = nock("https://my-awesome-api.fake")
.get("/")
.query({ page: 2 })
.reply(200, { id: 2 })
.persist();

const children = jest.fn();
children.mockReturnValue(<div />);

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake">
<Get path="">{children}</Get>
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-awesome-api.fake" queryParams={{ page: 2 }}>
<Get path="">{children}</Get>
</RestfulProvider>,
);

await wait(() => expect(firstAPI.isDone()).toBeTruthy());
await wait(() => expect(secondAPI.isDone()).toBeTruthy());
});
it("should refetch when requestOptions change", async () => {
const firstAPI = nock("https://my-awesome-api.fake")
.get("/")
.matchHeader("header1", "value1")
.reply(200, { id: 1 });
const secondAPI = nock("https://my-awesome-api.fake")
.get("/")
.matchHeader("header2", "value2")
.reply(200, { id: 2 });

const children = jest.fn();
children.mockReturnValue(<div />);

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake" requestOptions={() => ({ headers: { header1: "value1" } })}>
<Get path="">{children}</Get>
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-awesome-api.fake" requestOptions={() => ({ headers: { header2: "value2" } })}>
<Get path="">{children}</Get>
</RestfulProvider>,
);

await wait(() => expect(firstAPI.isDone()).toBeTruthy());
await wait(() => expect(secondAPI.isDone()).toBeTruthy());
});
});

describe("refetch after get props update", () => {
it("should not refetch when base, path or resolve don't change", async () => {
let apiCalls = 0;
nock("https://my-awesome-api.fake")
Expand Down
7 changes: 5 additions & 2 deletions src/Get.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,17 @@ class ContextlessGet<TData, TError, TQueryParams, TPathParams = unknown> extends
}

public componentDidUpdate(prevProps: GetProps<TData, TError, TQueryParams, TPathParams>) {
const { base, parentPath, path, resolve, queryParams } = prevProps;
const { base, parentPath, path, resolve, queryParams, requestOptions } = prevProps;
if (
base !== this.props.base ||
parentPath !== this.props.parentPath ||
path !== this.props.path ||
!isEqual(queryParams, this.props.queryParams) ||
// both `resolve` props need to _exist_ first, and then be equivalent.
(resolve && this.props.resolve && resolve.toString() !== this.props.resolve.toString())
(resolve && this.props.resolve && resolve.toString() !== this.props.resolve.toString()) ||
(requestOptions &&
this.props.requestOptions &&
requestOptions.toString() !== this.props.requestOptions.toString())
) {
if (!this.props.lazy) {
this.fetch();
Expand Down
132 changes: 131 additions & 1 deletion src/useGet.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,137 @@ describe("useGet hook", () => {
});
});

describe("refetch after update", () => {
describe("refetch after provider props update", () => {
it("should refetch when base changes", async () => {
const firstAPI = nock("https://my-awesome-api.fake")
.get("/")
.reply(200, { id: 1 });

const secondAPI = nock("https://my-new-api.fake")
.get("/")
.reply(200, { id: 2 });

const children = jest.fn();
children.mockReturnValue(<div />);

const MyAwesomeComponent: React.FC<{ path: string }> = ({ path }) => {
const params = useGet<{ id: number }>({ path });
return children(params);
};

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake">
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-new-api.fake">
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

expect(firstAPI.isDone()).toBeTruthy();
expect(secondAPI.isDone()).toBeTruthy();
});
it("should refetch when parentPath changes", async () => {
let apiCalls = 0;
nock("https://my-awesome-api.fake")
.get("/")
.reply(200, () => ++apiCalls);

const children = jest.fn();
children.mockReturnValue(<div />);

const MyAwesomeComponent: React.FC<{ path: string }> = ({ path }) => {
const params = useGet<{ id: number }>({ path });
return children(params);
};

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake">
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-awesome-api.fake" parentPath="parent">
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

expect(apiCalls).toEqual(2);
});
it("should refetch when queryParams change", async () => {
nock("https://my-awesome-api.fake")
.get("/")
.reply(200, { id: 0 });
nock("https://my-awesome-api.fake")
.get("/")
.query({ page: 2 })
.reply(200, { id: 1 });

const children = jest.fn();
children.mockReturnValue(<div />);

const MyAwesomeComponent: React.FC<{ path: string }> = ({ path }) => {
const params = useGet<{ id: number }, any, { page: number }>({ path });
return children(params);
};

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake" queryParams={{ page: 1 }}>
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-awesome-api.fake" queryParams={{ page: 2 }}>
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

await wait(() => expect(children).toBeCalledTimes(3));
expect(children.mock.calls[2][0].loading).toEqual(false);
expect(children.mock.calls[2][0].data).toEqual({ id: 1 });
});
it("should refetch when requestOptions change", async () => {
nock("https://my-awesome-api.fake")
.get("/")
.matchHeader("header1", "value1")
.reply(200, { id: 0 });
nock("https://my-awesome-api.fake")
.get("/")
.matchHeader("header2", "value2")
.reply(200, { id: 1 });

const children = jest.fn();
children.mockReturnValue(<div />);

const MyAwesomeComponent: React.FC<{ path: string }> = ({ path }) => {
const params = useGet<{ id: number }, any, { page: number }>({ path });
return children(params);
};

const { rerender } = render(
<RestfulProvider base="https://my-awesome-api.fake" requestOptions={() => ({ headers: { header1: "value1" } })}>
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

rerender(
<RestfulProvider base="https://my-awesome-api.fake" requestOptions={() => ({ headers: { header2: "value2" } })}>
<MyAwesomeComponent path="" />
</RestfulProvider>,
);

await wait(() => expect(children).toBeCalledTimes(4));
expect(children.mock.calls[3][0].loading).toEqual(false);
expect(children.mock.calls[3][0].data).toEqual({ id: 1 });
});
});

describe("refetch after useGet props update", () => {
it("should not refetch when base, path or resolve don't change", () => {
let apiCalls = 0;
nock("https://my-awesome-api.fake")
Expand Down
15 changes: 14 additions & 1 deletion src/useGet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,20 @@ export function useGet<TData = any, TError = any, TQueryParams = { [key: string]
return () => {
abort();
};
}, [props.lazy, props.mock, props.path, props.base, props.resolve, props.queryParams, props.requestOptions, abort]);
}, [
props.lazy,
props.mock,
props.path,
props.base,
props.resolve,
props.queryParams,
props.requestOptions,
context.base,
context.parentPath,
context.queryParams,
context.requestOptions,
abort,
]);

return {
...state,
Expand Down

0 comments on commit c5c0fe0

Please sign in to comment.