Merge pull request #23 from pleshevskiy/task-22

feat: add refetch function to hooks state
This commit is contained in:
Dmitriy Pleshevskiy 2020-12-20 11:25:24 +02:00 committed by GitHub
commit 70da8b3ad0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 63 additions and 25 deletions

View file

@ -8,7 +8,7 @@ export enum Method {
DELETE = 'DELETE', DELETE = 'DELETE',
} }
export type Endpoint<R, V, P = never> = Readonly<{ export type Endpoint<R, _V, P = never> = Readonly<{
method: Method; method: Method;
url: string | ((params: P) => string); url: string | ((params: P) => string);
headers?: Record<string, string>; headers?: Record<string, string>;

View file

@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from 'react'; import React from 'react';
import invariant from 'tiny-invariant'; import invariant from 'tiny-invariant';
import isEqual from 'lodash.isequal'; import isEqual from 'lodash.isequal';
import { useClient } from './client-hook'; import { useClient } from './client-hook';
@ -23,6 +23,10 @@ export type LazyRequestHandlerConfig<R, V, P> = Readonly<
export type RequestHandler<R, V, P> = (config?: LazyRequestHandlerConfig<R, V, P>) => Promise<R | null>; export type RequestHandler<R, V, P> = (config?: LazyRequestHandlerConfig<R, V, P>) => Promise<R | null>;
export type RefetchRequestHandler = () => void;
export type PublicRequestStateWithRefetch<R> = PublicRequestState<R> & { refetch: RefetchRequestHandler };
export function useLazyRequest< export function useLazyRequest<
E extends Endpoint<R, V, P>, E extends Endpoint<R, V, P>,
R = ExtractEndpointResponse<E>, R = ExtractEndpointResponse<E>,
@ -31,7 +35,7 @@ export function useLazyRequest<
>( >(
endpoint: E, endpoint: E,
config?: LazyRequestConfig<R, V, P>, config?: LazyRequestConfig<R, V, P>,
): [RequestHandler<R, V, P>, PublicRequestState<R>] { ): [RequestHandler<R, V, P>, PublicRequestStateWithRefetch<R>] {
const [client] = useClient(); const [client] = useClient();
const { defaultHeaders } = useRequestContext(); const { defaultHeaders } = useRequestContext();
const [state, dispatch] = React.useReducer<React.Reducer<RequestState<R>, RequestAction<R>>>( const [state, dispatch] = React.useReducer<React.Reducer<RequestState<R>, RequestAction<R>>>(
@ -42,8 +46,9 @@ export function useLazyRequest<
isCalled: false, isCalled: false,
} }
); );
const [prevHandlerConfig, setPrevHandlerConfig] = React.useState<LazyRequestHandlerConfig<R, V, P> | null>(null);
const transformResponseData = useCallback( const transformResponseData = React.useCallback(
(data: unknown): R => { (data: unknown): R => {
return isFunction(endpoint.transformResponseData) ? return isFunction(endpoint.transformResponseData) ?
endpoint.transformResponseData(data) endpoint.transformResponseData(data)
@ -98,6 +103,8 @@ export function useLazyRequest<
dispatch({ type: 'call', headers, variables, params }); dispatch({ type: 'call', headers, variables, params });
setPrevHandlerConfig(handlerConfig ?? {});
return client return client
.request<R>({ .request<R>({
...endpoint, ...endpoint,
@ -128,12 +135,25 @@ export function useLazyRequest<
[state, config, client, endpoint, defaultHeaders, transformResponseData] [state, config, client, endpoint, defaultHeaders, transformResponseData]
); );
const refetch = React.useCallback(
() => {
if (prevHandlerConfig != null) {
handler({
...prevHandlerConfig,
force: true,
});
}
},
[handler, prevHandlerConfig]
);
return [ return [
handler, handler,
{ {
data: state.data, data: state.data,
loading: state.loading, loading: state.loading,
isCalled: state.isCalled, isCalled: state.isCalled,
refetch,
}, },
]; ];
} }

View file

@ -1,20 +1,32 @@
import { ClientResponse } from './client'; import { ClientResponse } from './client';
export type RequestState<R> = Readonly<{ export type PublicRequestState<R> = Readonly<{
data: R | null; data: R | null;
loading: boolean; loading: boolean;
isCalled: boolean; isCalled: boolean;
}>;
export type RequestState<R> = PublicRequestState<R> & Readonly<{
prevHeaders?: Record<string, string>; prevHeaders?: Record<string, string>;
prevVariables?: Record<string, any>; prevVariables?: Record<string, any>;
prevParams?: Record<string, any> prevParams?: Record<string, any>;
}> }>
export type PublicRequestState<R> = Pick<RequestState<R>, 'data' | 'loading' | 'isCalled'>;
export type RequestAction<R> = export type RequestAction<R> =
| { type: 'call', headers: Record<string, string>, variables: Record<string, any>, params?: Record<string, any> } | {
| { type: 'success', response: ClientResponse<R> } type: 'call',
| { type: 'failure', response: ClientResponse<R> } headers: Record<string, string>,
variables: Record<string, any>,
params?: Record<string, any>
}
| {
type: 'success',
response: ClientResponse<R>
}
| {
type: 'failure',
response: ClientResponse<R>
}
export function requestReducer<R>(state: RequestState<R>, action: RequestAction<R>) { export function requestReducer<R>(state: RequestState<R>, action: RequestAction<R>) {
switch (action.type) { switch (action.type) {

View file

@ -6,7 +6,7 @@ export declare enum Method {
PATCH = "PATCH", PATCH = "PATCH",
DELETE = "DELETE" DELETE = "DELETE"
} }
export declare type Endpoint<R, V, P = never> = Readonly<{ export declare type Endpoint<R, _V, P = never> = Readonly<{
method: Method; method: Method;
url: string | ((params: P) => string); url: string | ((params: P) => string);
headers?: Record<string, string>; headers?: Record<string, string>;

View file

@ -12,4 +12,8 @@ export declare type LazyRequestHandlerConfig<R, V, P> = Readonly<LazyRequestConf
force?: boolean; force?: boolean;
}>; }>;
export declare type RequestHandler<R, V, P> = (config?: LazyRequestHandlerConfig<R, V, P>) => Promise<R | null>; export declare type RequestHandler<R, V, P> = (config?: LazyRequestHandlerConfig<R, V, P>) => Promise<R | null>;
export declare function useLazyRequest<E extends Endpoint<R, V, P>, R = ExtractEndpointResponse<E>, V = ExtractEndpointVariables<E>, P = ExtractEndpointParams<E>>(endpoint: E, config?: LazyRequestConfig<R, V, P>): [RequestHandler<R, V, P>, PublicRequestState<R>]; export declare type RefetchRequestHandler = () => void;
export declare type PublicRequestStateWithRefetch<R> = PublicRequestState<R> & {
refetch: RefetchRequestHandler;
};
export declare function useLazyRequest<E extends Endpoint<R, V, P>, R = ExtractEndpointResponse<E>, V = ExtractEndpointVariables<E>, P = ExtractEndpointParams<E>>(endpoint: E, config?: LazyRequestConfig<R, V, P>): [RequestHandler<R, V, P>, PublicRequestStateWithRefetch<R>];

View file

@ -1,4 +1,4 @@
import React, { useCallback } from 'react'; import React from 'react';
import invariant from 'tiny-invariant'; import invariant from 'tiny-invariant';
import isEqual from 'lodash.isequal'; import isEqual from 'lodash.isequal';
import { useClient } from './client-hook'; import { useClient } from './client-hook';
@ -13,7 +13,8 @@ export function useLazyRequest(endpoint, config) {
loading: false, loading: false,
isCalled: false, isCalled: false,
}); });
const transformResponseData = useCallback((data) => { const [prevHandlerConfig, setPrevHandlerConfig] = React.useState(null);
const transformResponseData = React.useCallback((data) => {
return isFunction(endpoint.transformResponseData) ? return isFunction(endpoint.transformResponseData) ?
endpoint.transformResponseData(data) endpoint.transformResponseData(data)
: data; : data;
@ -46,6 +47,7 @@ export function useLazyRequest(endpoint, config) {
const onComplete = (_b = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.onComplete) !== null && _b !== void 0 ? _b : config === null || config === void 0 ? void 0 : config.onComplete; const onComplete = (_b = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.onComplete) !== null && _b !== void 0 ? _b : config === null || config === void 0 ? void 0 : config.onComplete;
const onFailure = (_c = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.onFailure) !== null && _c !== void 0 ? _c : config === null || config === void 0 ? void 0 : config.onFailure; const onFailure = (_c = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.onFailure) !== null && _c !== void 0 ? _c : config === null || config === void 0 ? void 0 : config.onFailure;
dispatch({ type: 'call', headers, variables, params }); dispatch({ type: 'call', headers, variables, params });
setPrevHandlerConfig(handlerConfig !== null && handlerConfig !== void 0 ? handlerConfig : {});
return client return client
.request(Object.assign(Object.assign({}, endpoint), { url: endpointUrl, headers, .request(Object.assign(Object.assign({}, endpoint), { url: endpointUrl, headers,
variables, variables,
@ -64,12 +66,18 @@ export function useLazyRequest(endpoint, config) {
return null; return null;
}); });
}, [state, config, client, endpoint, defaultHeaders, transformResponseData]); }, [state, config, client, endpoint, defaultHeaders, transformResponseData]);
const refetch = React.useCallback(() => {
if (prevHandlerConfig != null) {
handler(Object.assign(Object.assign({}, prevHandlerConfig), { force: true }));
}
}, [handler, prevHandlerConfig]);
return [ return [
handler, handler,
{ {
data: state.data, data: state.data,
loading: state.loading, loading: state.loading,
isCalled: state.isCalled, isCalled: state.isCalled,
refetch,
}, },
]; ];
} }

5
target/reducer.d.ts vendored
View file

@ -1,13 +1,14 @@
import { ClientResponse } from './client'; import { ClientResponse } from './client';
export declare type RequestState<R> = Readonly<{ export declare type PublicRequestState<R> = Readonly<{
data: R | null; data: R | null;
loading: boolean; loading: boolean;
isCalled: boolean; isCalled: boolean;
}>;
export declare type RequestState<R> = PublicRequestState<R> & Readonly<{
prevHeaders?: Record<string, string>; prevHeaders?: Record<string, string>;
prevVariables?: Record<string, any>; prevVariables?: Record<string, any>;
prevParams?: Record<string, any>; prevParams?: Record<string, any>;
}>; }>;
export declare type PublicRequestState<R> = Pick<RequestState<R>, 'data' | 'loading' | 'isCalled'>;
export declare type RequestAction<R> = { export declare type RequestAction<R> = {
type: 'call'; type: 'call';
headers: Record<string, string>; headers: Record<string, string>;

View file

@ -3,11 +3,4 @@ import { LazyRequestConfig } from './lazy-request-hook';
export declare type RequestConfig<R, V, P> = Readonly<LazyRequestConfig<R, V, P> & { export declare type RequestConfig<R, V, P> = Readonly<LazyRequestConfig<R, V, P> & {
skip?: boolean; skip?: boolean;
}>; }>;
export declare function useRequest<E extends Endpoint<R, V, P>, R = ExtractEndpointResponse<E>, V = ExtractEndpointVariables<E>, P = ExtractEndpointParams<E>>(endpoint: E, config?: RequestConfig<R, V, P>): Pick<Readonly<{ export declare function useRequest<E extends Endpoint<R, V, P>, R = ExtractEndpointResponse<E>, V = ExtractEndpointVariables<E>, P = ExtractEndpointParams<E>>(endpoint: E, config?: RequestConfig<R, V, P>): import("./lazy-request-hook").PublicRequestStateWithRefetch<R>;
data: R | null;
loading: boolean;
isCalled: boolean;
prevHeaders?: Record<string, string> | undefined;
prevVariables?: Record<string, any> | undefined;
prevParams?: Record<string, any> | undefined;
}>, "loading" | "data" | "isCalled">;