Skip to content
This repository has been archived by the owner on Nov 11, 2023. It is now read-only.

Commit

Permalink
Add a onMutate callback.
Browse files Browse the repository at this point in the history
  • Loading branch information
fabien0102 committed Jul 29, 2019
1 parent be0a574 commit 708ee4c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 7 deletions.
27 changes: 27 additions & 0 deletions src/Mutate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,34 @@ describe("Mutate", () => {

// No `expect` here, it's just to test if the types are correct 😉
});

it("should call onMutate", async () => {
nock("https://my-awesome-api.fake")
.post("/")
.reply(200, { id: 1 });

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

const onMutate = jest.fn();

// setup - first render
render(
<RestfulProvider base="https://my-awesome-api.fake">
<Mutate verb="POST" path="" onMutate={onMutate}>
{children}
</Mutate>
</RestfulProvider>,
);

// call mutate
await wait(() => expect(children.mock.calls.length).toBe(1));
await children.mock.calls[0][0]();

expect(onMutate).toHaveBeenCalled();
});
});

describe("PUT", () => {
it("should deal with empty response", async () => {
nock("https://my-awesome-api.fake")
Expand Down
12 changes: 12 additions & 0 deletions src/Mutate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ export interface MutateProps<TData, TError, TQueryParams, TRequestBody> {
* @param actions - a key/value map of HTTP verbs, aliasing destroy to DELETE.
*/
children: (mutate: MutateMethod<TData, TRequestBody>, states: States<TData, TError>, meta: Meta) => React.ReactNode;
/**
* Callback called after the mutation is done.
*
* @param body - Body given to mutate
* @param data - Response data
*/
onMutate?: (body: TRequestBody, data: TData) => void;
}

/**
Expand Down Expand Up @@ -209,6 +216,11 @@ class ContextlessMutate<TData, TError, TQueryParams, TRequestBody> extends React
}

this.setState({ loading: false });

if (this.props.onMutate) {
this.props.onMutate(body, data);
}

return data;
};

Expand Down
18 changes: 16 additions & 2 deletions src/useMutate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,20 @@ describe("useMutate", () => {
}
});

it("should call onMutation", async () => {
nock("https://my-awesome-api.fake")
.post("/")
.reply(200, { ok: true });

const wrapper = ({ children }) => (
<RestfulProvider base="https://my-awesome-api.fake">{children}</RestfulProvider>
);
const onMutate = jest.fn();
const { result } = renderHook(() => useMutate("POST", "", { onMutate }), { wrapper });
await result.current.mutate({ foo: "bar" });
expect(onMutate).toHaveBeenCalled();
});

it("should deal with non standard server error response (nginx style)", async () => {
nock("https://my-awesome-api.fake")
.post("/")
Expand Down Expand Up @@ -407,7 +421,7 @@ describe("useMutate", () => {
}

type UseDeleteMyCustomEndpoint = Omit<
UseMutateProps<MyCustomEnpointResponse, MyCustomEnpointQueryParams>,
UseMutateProps<MyCustomEnpointResponse, MyCustomEnpointQueryParams, {}>,
"path" | "verb"
>;
const useDeleteMyCustomEndpoint = (props?: UseDeleteMyCustomEndpoint) =>
Expand Down Expand Up @@ -454,7 +468,7 @@ describe("useMutate", () => {
}

type UseDeleteMyCustomEndpoint = Omit<
UseMutateProps<MyCustomEnpointResponse, MyCustomEnpointQueryParams>,
UseMutateProps<MyCustomEnpointResponse, MyCustomEnpointQueryParams, {}>,
"path" | "verb"
>;
const useDeleteMyCustomEndpoint = (props?: UseDeleteMyCustomEndpoint) =>
Expand Down
21 changes: 16 additions & 5 deletions src/useMutate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ import { MutateMethod, MutateState } from "./Mutate";
import { Omit, resolvePath, UseGetProps } from "./useGet";
import { processResponse } from "./util/processResponse";

export interface UseMutateProps<TData, TQueryParams>
export interface UseMutateProps<TData, TQueryParams, TRequestBody>
extends Omit<UseGetProps<TData, TQueryParams>, "lazy" | "debounce"> {
/**
* What HTTP verb are we using?
*/
verb: "POST" | "PUT" | "PATCH" | "DELETE";
/**
* Callback called after the mutation is done.
*
* @param body - Body given to mutate
* @param data - Response data
*/
onMutate?: (body: TRequestBody, data: TData) => void;
}

export interface UseMutateReturn<TData, TError, TRequestBody> extends MutateState<TData, TError> {
Expand All @@ -25,13 +32,13 @@ export interface UseMutateReturn<TData, TError, TRequestBody> extends MutateStat
}

export function useMutate<TData = any, TError = any, TQueryParams = { [key: string]: any }, TRequestBody = any>(
props: UseMutateProps<TData, TQueryParams>,
props: UseMutateProps<TData, TQueryParams, TRequestBody>,
): UseMutateReturn<TData, TError, TRequestBody>;

export function useMutate<TData = any, TError = any, TQueryParams = { [key: string]: any }, TRequestBody = any>(
verb: UseMutateProps<TData, TQueryParams>["verb"],
verb: UseMutateProps<TData, TQueryParams, TRequestBody>["verb"],
path: string,
props?: Omit<UseMutateProps<TData, TQueryParams>, "path" | "verb">,
props?: Omit<UseMutateProps<TData, TQueryParams, TRequestBody>, "path" | "verb">,
): UseMutateReturn<TData, TError, TRequestBody>;

export function useMutate<
Expand All @@ -40,7 +47,7 @@ export function useMutate<
TQueryParams = { [key: string]: any },
TRequestBody = any
>(): UseMutateReturn<TData, TError, TRequestBody> {
const props: UseMutateProps<TData, TQueryParams> =
const props: UseMutateProps<TData, TQueryParams, TRequestBody> =
typeof arguments[0] === "object" ? arguments[0] : { ...arguments[2], path: arguments[1], verb: arguments[0] };

const context = useContext(Context);
Expand Down Expand Up @@ -158,6 +165,10 @@ export function useMutate<

setState(prevState => ({ ...prevState, loading: false }));

if (props.onMutate) {
props.onMutate(body, data);
}

return data;
},
[context.base, context.requestOptions, context.resolve, state.error, state.loading, path],
Expand Down

0 comments on commit 708ee4c

Please sign in to comment.