Questrar is a simple React request state tracker for managing states of requests.
Installation
yarn add questrar npm install questrar
Why Questrar?
The state of an app request is necessary to user's interactivity and experience. Continually, App needs to fetch data from server or do a complex computation. It's important to let the user know if request is still loading, failed or successful. This can be repetitive and hard to work around with and you are likely going to need in every application which fetches data from server or anywhere else.
Questrar alleviates those needs into a simple <Request />
wrapper - with the help of
React's composability making it easy to control, track request,
show loading icons and failed messages and other UI transformations based on a state of specific request.
Working with redux
API section
SeeA request state is typed as
// @flow
A default request state (initial request state or provided when request state is not found by id)
const defaultRequestState: RequestState = id: 'newRequestId' pending: false success: false failed: false successCount: 0 failureCount: 0 clean: true message: undefined
A requestState is simple to use in a React component by wrapping the component tree with the Provider
.
stateProvider
prop is required.
import Provider from 'questrar';import type StateProvider from 'questrar';import defaultRequestStateProvider from 'questrar/store'; const stateProvider: StateProvider = ; const AppMain = <Provider => <App /> </Provider>
Now you can use the Request
component in any of your components anywhere deep, anyhow deep.
const App = <Request ="id"> <View /></Request>
A Request
component requires an id which will be used to track a request.
An id is recommended to be a string
or number
.
Symbol
should be used carefully since Symbol()
creates a new different object every time.
A request id should be a bit unique to a particular subject context. For instance, if you have a user account which can have many queries to api, (fetch user, edit user, delete user, upload photo), its bearable not to use a single request id (which obviously may be userId) for all these actions on the user. Instead, you can just concat to do
const fetchProfileRequestId = `_fetch`;const deleteUserId = `_delete`
The consequence of using same id looks like showing a pending delete when indeed user is uploading a photo.
You don't have to create a request state inside a component. You just provide an id. If the id has no requestState, a default one is returned but never saved. A request state is saved if there is an update action on the request state
; const UserProfile = { return <Request id=userId pendOnMount > <ProfileView data=data /> </Request> ;}
Where you explicitly want to access the request state object, you can use the inject
prop on Request
;
<Request = > <ProfileView = /></Request>
inject
can be a boolean or a function with signature (request: RequestProp) => Object
which would be received by the underlying component.
const UserProfile = userId data const mapToButtonProps = request: RequestProp return loading: requestdatapending disable: requestdatapending || requestdatasuccess || requestdatafailureCount > 5//disable after 5 request failures requestactions ; ; return <Request = = > <Button >Fetch Profile</Button> </Request> ;
At some point where the Request
component isn't that helpful to use with your component,
you can try with the withRequest
HOC and expect the request
state as a prop.
import withRequest from 'questrar'; type Props = userId: string data: Object request: RequestProp const UserProfile = userId data request : Prop ifrequestdatadirty const requestId = requestdataid; requestactions return <div> requestdatafailed && <Banner = /> requestdatasuccess && <ProfileView = /> <Button = = > Fetch User Profile </Button> </div> ;; propsuserId UserProfile;
withRequest
takes these options:
withRequest
takes an optional single id or optional list of ids or optional function
that can convert the props of the wrapped component to a single id or list of ids.
withRequest
automatically takes options.id
(if there is) if props.id
is empty.
Thats to say props.id
has precedence over options.id
.
However, if you require props.id
and options.id
to merge, set mergeIdSources
to true.
This will merge props.id
and options.id
with no duplicates and
return an object typed as RequestMapProp
similar to RequestProp
.
Any of props.id
or options.id
is optional. If no id is found, an empty object is returned
Note: If a single id is provided by
props.id
oroptions.id
or both(ifmergeIdSources
istrue
), aRequestProp
is returned instead ofRequestMapProp
Feedback
Any feedback and PR contributions will be appreciated regardless.
Credits
- Inspired by Christian Kaps @akkie