diff --git a/package-lock.json b/package-lock.json index 893670a..64d6bfd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-rest-request", - "version": "0.5.0", + "version": "0.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/endpoint.ts b/src/endpoint.ts index 70568b0..16570a5 100644 --- a/src/endpoint.ts +++ b/src/endpoint.ts @@ -8,13 +8,16 @@ export enum Method { DELETE = 'DELETE', } -export type Endpoint = Readonly<{ +export type Endpoint = Readonly<{ + _?: V; // Temporary hack to extract the type of variables. Do not use it in real endpoints. method: Method; url: string | ((params: P) => string); headers?: Record; transformResponseData?: (data: any) => R; }> +export type AnyEndpoint = Endpoint; + export type ExtractEndpointResponse = E extends Endpoint ? R : E extends Endpoint ? R : never; export type ExtractEndpointVariables = E extends Endpoint ? V : E extends Endpoint ? V : never; export type ExtractEndpointParams = E extends Endpoint ? P : never; diff --git a/src/lazy-request-hook.ts b/src/lazy-request-hook.ts index c9c807d..53e7cb4 100644 --- a/src/lazy-request-hook.ts +++ b/src/lazy-request-hook.ts @@ -2,13 +2,13 @@ import React from 'react'; import invariant from 'tiny-invariant'; import isEqual from 'lodash.isequal'; import { useClient } from './client-hook'; -import { Endpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; -import { PublicRequestState, RequestAction, requestReducer, RequestState } from './reducer'; +import { AnyEndpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; +import { PublicRequestState, RequestReducer, requestReducer } from './reducer'; import { useRequestContext } from './request-context'; import { ClientResponse } from './client'; import { isFunction } from './misc'; -export type LazyRequestConfig = Readonly<{ +export type LazyRequestConfig = Readonly<{ variables?: V; params?: P; headers?: Record; @@ -16,29 +16,33 @@ export type LazyRequestConfig = Readonly<{ onFailure?: (res: ClientResponse) => unknown; }> -export type LazyRequestHandlerConfig = Readonly< - LazyRequestConfig +export type LazyRequestConfigFromEndpoint = LazyRequestConfig< + ExtractEndpointResponse, + ExtractEndpointVariables, + ExtractEndpointParams +>; + +export type LazyRequestHandlerConfig = Readonly< + LazyRequestConfigFromEndpoint & { force?: boolean } > -export type RequestHandler = (config?: LazyRequestHandlerConfig) => Promise; +export type RequestHandler = + (config?: LazyRequestHandlerConfig) => Promise | null>; export type RefetchRequestHandler = () => void; -export type PublicRequestStateWithRefetch = PublicRequestState & { refetch: RefetchRequestHandler }; +export type PublicRequestStateWithRefetch = + PublicRequestState> + & { refetch: RefetchRequestHandler }; -export function useLazyRequest< - E extends Endpoint, - R = ExtractEndpointResponse, - V = ExtractEndpointVariables, - P = ExtractEndpointParams ->( +export function useLazyRequest( endpoint: E, - config?: LazyRequestConfig, -): [RequestHandler, PublicRequestStateWithRefetch] { + config?: LazyRequestConfigFromEndpoint, +): [RequestHandler, PublicRequestStateWithRefetch] { const [client] = useClient(); const { defaultHeaders } = useRequestContext(); - const [state, dispatch] = React.useReducer, RequestAction>>( + const [state, dispatch] = React.useReducer>>( requestReducer, { data: null, @@ -46,24 +50,24 @@ export function useLazyRequest< isCalled: false, } ); - const [prevHandlerConfig, setPrevHandlerConfig] = React.useState | null>(null); + const [prevHandlerConfig, setPrevHandlerConfig] = React.useState | null>(null); const transformResponseData = React.useCallback( - (data: unknown): R => { + (data: unknown): ExtractEndpointResponse => { return isFunction(endpoint.transformResponseData) ? endpoint.transformResponseData(data) - : data as R; + : data as ExtractEndpointResponse; }, [endpoint] ); const handler = React.useCallback( - (handlerConfig?: LazyRequestHandlerConfig) => { + (handlerConfig?: LazyRequestHandlerConfig) => { if (state?.loading) { return Promise.resolve(null); } - let params: P | undefined; + let params: ExtractEndpointParams | undefined; let endpointUrl: string; let isSameRequest = true; if (isFunction(endpoint.url)) { @@ -106,7 +110,7 @@ export function useLazyRequest< setPrevHandlerConfig(handlerConfig ?? {}); return client - .request({ + .request>({ ...endpoint, url: endpointUrl, headers, diff --git a/src/reducer.ts b/src/reducer.ts index 5607fcf..409ef63 100644 --- a/src/reducer.ts +++ b/src/reducer.ts @@ -28,6 +28,8 @@ export type RequestAction = response: ClientResponse } +export type RequestReducer = React.Reducer, RequestAction> + export function requestReducer(state: RequestState, action: RequestAction) { switch (action.type) { case 'call': { diff --git a/src/request-hook.ts b/src/request-hook.ts index 376e529..a66ed8a 100644 --- a/src/request-hook.ts +++ b/src/request-hook.ts @@ -1,23 +1,18 @@ import React from 'react'; import invariant from 'tiny-invariant'; -import { Endpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables, Method } from './endpoint'; -import { LazyRequestConfig, useLazyRequest } from './lazy-request-hook'; +import { AnyEndpoint, Method } from './endpoint'; +import { LazyRequestConfigFromEndpoint, useLazyRequest } from './lazy-request-hook'; -export type RequestConfig = Readonly< - LazyRequestConfig +export type RequestConfigFromEndpoint = Readonly< + LazyRequestConfigFromEndpoint & { skip?: boolean, } > -export function useRequest< - E extends Endpoint, - R = ExtractEndpointResponse, - V = ExtractEndpointVariables, - P = ExtractEndpointParams ->( +export function useRequest( endpoint: E, - config?: RequestConfig, + config?: RequestConfigFromEndpoint, ) { invariant( endpoint.method !== Method.DELETE,