Redux Fetcher Compose is a library for data fetching and integrate @reduxjs/toolkit for React application
It features:
- Support Hooks, React Component, and Redux action to fetch and get data from API.
- Auto init reducer and action. It means, you not must declare a reducer to store response data.
- Support autosave response data to reducer base on URI (caching and prevent DRY code).
- Support transform response data getter.
- Support Abort Controller to abort request after unmount or client timeout.
- TypeScript ready.
- Support helper checks the status of data and requests.
- Add more hooks to trigger the request event.
- Can set timeout and parse the response for each request.
- Refetch request with previous props.
- All features supported by @reduxjs/toolkit
...and a lot more.
Inside your React project directory, run the following:
yarn add redux-fetcher-compose
Or with npm:
npm install redux-fetcher-compose
You can checkout example at CodeSandbox
fetcher.ts
import {
createFetcher,
createService,
ResponseParsed,
} from 'redux-fetcher-compose'
interface ExampleFetcherProps {
type: string
}
interface Post {
id: string
name: string
description: string
}
type RootState = any // Root reducers type;
const serviceCommon = createService({
domain: 'https://example.com/api',
requestTimeout: 10000
})
const ENTRY_POINT = 'example'
const fetcher = createFetcher<
ExampleFetcherProps,
RootState,
ResponseParsed<Post[]>,
>({
id: 'Example',
shouldKeepData: true,
uri: ({ props }) => props.type,
service: serviceCommon,
requestInfo: () => {
return {
entry: ENTRY_POINT,
options: {
method: 'GET',
},
}
},
})
export const {
action: getExampleAction,
component: ExampleFetcher,
useFetcherCompose: useExampleFetcherCompose,
useGetter: useExampleGetter,
useFetcher: useExampleFetcher
} = fetcher
App.tsx
import React from 'react'
import {
createAppState,
DataProvider
} from 'redux-fetcher-compose'
import { useExampleFetcherCompose } from './fetcher.ts'
const appState = createAppState({
enableReduxDevTools: true,
reducers: {}, // Root reducers
initialState: {},
})
export default function App () {
const [getter, refetch, abortController] = useExampleFetcherCompose({
type: 'news'
})
const handleRefetch = () => {
refetch()
}
return (
<DataProvider appState={appState}>
<h1>Hello Redux Fetcher Compose</h1>
<button onClick={handleRefetch}>Refetch</button>
<p>Fetcher data: {JSON.stringify(getter)}</p>
</DataProvider>
)
}
The function to create Redux store and app state context.
const appState = createAppState(options)
options
: an object of config React Redux.enableReduxDevTools: boolean = false
: (optional) whether to enable Redux DevTools integration.reducers: ReducersMapObject = {}
: (optional) a single reducer function that will be used as the root reducer.initialState: Object = {}
: (optional) an initial state value to be passed to the Redux createStore function.middleware = []
: (optional) an array of Redux middleware to install.
store
: the store of Redux, it's enhanced some feature to use for fetcher.appStateContext
: the value of React context.enhancedStore
: the Redux store.dispatch
: the function to dispatch Redux action.
The React component to wrap all components of the application to used Redux.
<DataProvider appState={appState}>
<App />
</DataProvider>
appState
: the app state created bycreateAppState
function.children
: the React component children.
The React context
import { useContext } from 'react'
const appStateContext = useContext(AppStateContext)
enhancedStore
: the Redux store.dispatch
: the function to dispatch Redux action.
This React hook returns a reference to the same Redux store that was passed into the <DataProvider>
component.
const enhancedStore = useStore()
The function to create a request service. It's can config API domain, request timeout, parse response of request, pass request options. Moreover, it provides some hooks to trigger events: pre-request, request success, request error. The return value of the function used in the fetcher config as a parameter.
const service = createService(options);
options
: the object to config service.domain: string = undefined
: (optional) the base domain to request API.requestTimeout: number = undefined
: (optional) set time (millisecond) to set timeout for request.responseParser: ResponseParser = defaultResponseParser
: the function to parse response. It's decide response of request is success or error.optionsModifier: OptionModifier = undefined
: the function to modify request options default.preRequestHook: FnPreRequestHook = undefined
: the function to trigger pre request called.requestSuccessHook: FnRequestSuccessHook = undefined
: the function to trigger response succeed.requestErrorHook: FnRequestErrorHook = undefined
: the function to trigger response error.
service: Service
: the function to use in fetcher config.
ResponseParser
: (response) => PromiseOptionModifier
: (options) => RequestOptionsoptions
: { getAppStateContext, requestInfo }
FnPreRequestHook
: (options) => voidoptions
: { getAppStateContext, requestInfo, options }
FnRequestSuccessHook
: (options) => voidoptions
: { getAppStateContext, requestInfo, options, responseParsed }
FnRequestErrorHook
: (options) => voidoptions
: { getAppStateContext, requestInfo, options, responseParsed }
The function is used to define a fetcher. It's will create fetcher action, fetcher component, some hooks such as useFetcher, useGetter, useFetcherCompose.
/**
* @generator {FP}: Fetcher prop
* @generator {RS}: Root state,
* @generator {R}: Response,
* @generator {TR}: Transform response
* @param config
*/
const fetcher = createFetcher<FP, RS = any, R = any, TR = R>(config);
config
: the configuration object of fetcher.id: string = undefined
: (optional) the id of the fetcher. It's used to create a reducer to store response parsed. The field is optional, but if you want to use getter, that must be required.shouldKeepData: boolean = false
: (optional) the option help you keep fetcher data when component has use fetcher. It just work when you use useFetcher, useFetcherCompose, fetcher component.uri: FnFetcherURI = undefined
: (optional) the path to store response data in fetcher reducer. It useful when you call fetcher at many different contexts. Default fetcher will auto created path is@
.service: Service
: it service that fetcher used. Created bycreateService
.requestInfo: FnFetcherRequestInfo
: the function help declare are config of a request such as: domain, query, timeout, entry point, request options.shouldFetch: FnFetcherShouldFetch = defaultShouldFetch
: (optional) the function decided request call or not call. Default return true if the first call or current props different with previous props.preHandler: FnFetcherPreHandler = undefined
: (optional) the function will trigger before request called.onPending: FnFetcherOnPendingHandler = defaultOnPending
: (optional) the function will trigger while requesting API.onSuccess: FnFetcherOnSuccessHandler = defaultOnSuccess
: (optional) the function will trigger when response parsed was succeed.onError: FnFetcherOnErrorHandler = defaultOnError
: (optional) the function will trigger when response parsed was error.
action
: Redux action. When action dispatched then requesting API.component
: the React component. When component mounted then requesting API. But call or not call rely on the value returned of theshouldFetch
function.useFetcher
: the React hook to help you requesting API. But call or not call rely on the value returned of theshouldFetch
function.useGetter
: the React hook to help you get info of a request called stored in reducer base onuri
.useFetcherCompose
: the React hook that composeuseFetcher
anduseGetter
.
FnFetcherURI
: ({ props, getState }) => string;props
: Props to pass when use fetcher instance.getState
: Get state of root reducer.
Service
: ({ getAppStateContext, requestInfo, abortController, onPending, onSuccess, onError }) => PromiseFnFetcherRequestInfo
: (props, getAppStateContext) => RequestInfoRequestInfo
: is a object.domain?
: stringquery?
: string | {}timeout?
: numberentry
: stringoptions
: RequestInit
FnFetcherShouldFetch
: ({ props, state, localState} ) => boolean;state
: is a root state.localState
: is a state of fetcher base onuri
.
FnFetcherPreHandler
: ({ props, getState, getAppStateContext, dispatch, localState }) => voidFnFetcherOnPendingHandler
: ({ props, requestInfo, getState, localState, getAppStateContext, dispatch }) => anyFnFetcherOnSuccessHandler
: ({ props, requestInfo, getState, localState, getAppStateContext, dispatch }) => TR | RFnFetcherOnErrorHandler
: ({ props, requestInfo, error, localState, getState, getAppStateContext, dispatch }) => TR | R
action: (props?: FP, abortController?: AbortController ) => any
props
: is a prop to pass in fetcher.abortController
: is a instance ofnew AbortController()
- When you dispatch action will return value, that returned
onSuccess
oronError
function that pass to config fetcher.
const [refetch, abortController] = useFetcher(props?: FP, defer?: boolean);
- Hook params:
props
: is a props will pass to fetcher.defer
: If settrue
then will not request API when hook mounted.
- Hook return value:
refetch
is a function to refetch API:(newProps? FP) => TR
abortController
is a instance of AbortController.
const getter = useGetter(props?: FP, transform?: (getter) => { ... })
- Hook params:
props
: is a props will pass to fetcher.transform
: is a function to transform data before return.
- Hook return one object include properties:
-
fetchStatus
: is a fetch status. -
dataStatus
: is a fetcher data status. -
value
: is a value returned byonPending
,onSuccess
oronError
-
previous
: is a previous getter after one action dispatched to change getter data. -
currentProps
: is current props to passed in fetcher. -
previousProps
: is previous props to passed in fetcher. -
isStatus
: is a function to check status of requestisStatus: (dataStatus: DataStatus) => boolean;
-
isLoading
: it istrue
: API requesting.
-
const [getter, refetch, abortController] = useFetcherCompose(props?: FP, transform?: (getter) => { ... });
- Hook params:
props
: is a props will pass to fetcher.defer
: If settrue
then will not request API when hook mounted.
- Hook return value:
getter
is a value returned by transform function. It a object same value returned byuseGetter
hook.refetch
is a function to refetch API:(newProps? FP) => TR
abortController
is a instance of AbortController.
<Component {...props} transform={(getter) => { ... }}>
<SomethingComponent />
</Component>
-
Component
will pass all props into fetcher. -
Component
has specific prop istransform
.transform: (getter) => {...}
-
SomethingComponent
will passed two props:getter
andrefetch
.getter
is a value returned by transform function. It a object same value returned byuseGetter
hook.refetch
is a function to refetch API:(newProps? FP) => TR
The function to check should fetch or shouldn't fetch API. By check, fetch data status is initial or previous props different current props.
The status of fetcher data.
Initial
: is the initial state.Initializing
: pending on the first request.Initialized
: done on the first request.Updating
: pending since the first request.Updated
: done since the first request.Loading
: is requesting.Error
: the response was an error.Success
: the response was succeeded.Aborted
: the response was aborted.Timeout
: the response timeout.
The status of the request.
Init
Pending
Done
Aborted
Timeout
The function using the qs
library. Help you parse query string to object with default ignoreQueryPrefix = true
.
const queryObject = parseQuery(query: string, options: IParseOptions)
The function using the qs
library. Help you parse query string to object with default addQueryPrefix = true
.
const queryString = stringifyQuery(query: Object, options: IStringifyOptions)
Service
FnFetcherShouldFetch
FnFetcherPreHandler
FnFetcherRequestInfo
FnFetcherURI
FnFetcherOnPendingHandler
FnFetcherOnSuccessHandler
FnFetcherOnErrorHandler
ResponseParsed
Use SemVer for versioning. For the versions available, see the tags on this repository.
Lê Quí Nhất - [email protected]