##Purpose React Request Statuses gives an ability to avoid a lot of isLoading statuses in your project and provide the simple API for subscribing on 3 statuses of your async action.
- isLoading state
- isSuccess state
- Get Failed message
You had to create isLoading status for every action which needs handling in a template.
const initialState: UserReducer = {
// ...
user: {
//...
},
isLoading: false,
isSuccess: false,
errorMessage: '',
};
export const reducer = createReducer(initialState, {
[GET_USER_ASYNC.REQUEST.toString()]: (
state: UserReducer,
action: ActionType<User>,
) => {
// ...
state.isSuccess = false;
state.isLoading = true;
state.errorMessage = '';
},
[GET_USER_ASYNC.SUCCESS.toString()]: (
state: UserReducer,
action: ActionType<User>,
) => {
// ...
state.isSuccess = true;
state.isLoading = false;
},
[GET_USER_ASYNC.FAILURE.toString()]: (
state: UserReducer,
action: ActionType<ApiError>,
) => {
// ...
state.isSuccess = false;
state.isLoading = false;
state.errorMessage = action.payload.message;
},
});
After you no longer need to create an isLoading status, since you have the separate place with registered statuses for all actions.
const initialState: UserReducer = {
user: {
// ...
},
};
export const reducer = createReducer(initialState, {
[GET_USER_ASYNC.SUCCESS.toString()]: (
state: UserReducer,
action: ActionType<User>,
) => {
merge(state.user, action.payload);
},
});
Now if you are interested in some status of your action,it is simple to subscribe on that in the template.
import React, { useEffect } from "react";
import { useIsLoadingSelector, useIsSuccessSelector, useReasonFailedSelector } from "react-request-statuses";
import { GET_USER_ASYNC } from "@/store/user/actions";
export const SomeComponent = () => {
const isLoading = useIsLoadingSelector(GET_USER_ASYNC)
const isSuccess = useIsSuccessSelector(GET_USER_ASYNC)
const errorMessage = useReasonFailedSelector(GET_USER_ASYNC)
useEffect(() => {
if(errorMessage) {
alert(errorMessage)
}
}, [errorMessage])
useEffect(() => {
if(isSuccess) {
alert('Success!')
}
}, [isSuccess])
if(isLoading) {
return <FullScreenLoader />
}
return (
/// ..
)
}
Open a Terminal in the project root and run:
yarn add react-request-statuses
or
npm i react-request-statuses
- Add requestStatuses to your root reducer.
import { requestStatuses } from 'react-request-statuses';
export const rootReducer = combineReducers({
requestStatuses, // <- add here
// ...
})
- Then create async action for an action that you need to know a status using
createAsyncAction
fromreact-request-statuses
;
import { createAsyncAction } from 'react-request-statuses'; // <- required
export const GET_USER_ASYNC = createAsyncAction(ActionTypes.GET_USER);
- Then in a template using
useIsLoadingSelector
you can subscribe to loading state of your action.
import React, { useEffect } from "react";
import { useIsLoadingSelector, useIsSuccessSelector, useReasonFailedSelector } from "react-request-statuses";
import { GET_USER_ASYNC } from "@/store/user/actions";
import { useDispatch } from 'react-redux'
export const SomeComponent = () => {
const dispatch = useDispatch()
const isLoading = useIsLoadingSelector(GET_USER_ASYNC) // subscribe here
useEffect(() => {
dispatch(GET_USER_ASYNC.REQUEST()) // trigger request
}, [])
if(isLoading) {
return <FullScreenLoader />
}
return (
/// ..
)
}
- Update your Saga with call
SUCCESS
orFAILURE
statuses of your action.
import { GET_USER_ASYNC } from "@/store/user/actions"
import { api } from "@api"
export function* getUserSaga(): SagaIterator {
try {
const userDetails = yield call(api.user.getUser);
yield put(GET_USER_ASYNC.SUCCESS(userDetails.response)); // <- required
} catch (error) {
yield put(GET_USER_ASYNC.FAILURE(error)); // <- required
}
}
Allow subscribing to handle isLoading state.
export const SomeComponent = () => {
const isLoading = useIsLoadingSelector(GET_USER_ASYNC)
// Also you may subscribe for array of actions
const isLoading = useIsLoadingSelector([GET_USER_ASYNC, UPDATE_USER_ASYNC])
return (
// ...
)
}
Return true if request has been successful
const isSuccess = useIsSuccessSelector(GET_USER_ASYNC)
Return success payload
// somewhere
dispatch(GET_USER_ASYNC.SUCCESS({ id: 1, name: 'Jhon' }))
const payload = useSuccessPayloadSelector(GET_USER_ASYNC)
// { id: 1, name: 'Jhon' }
Return true if request has been failed
const isFailed = useIsFailedSelector(GET_USER_ASYNC)
Return error message
// somewhere
dispatch(GET_USER_ASYNC.FAILURE({ code: 401, message: 'Unauthorized' }))
const errorMessage = useReasonFailedSelector(GET_USER_ASYNC)
// 'Unauthorized'
Create the subscription for an action
export const SomeComponent = () => {
const getUserSubscription = useActionSubscription(GET_USER_ASYNC)
const successCallback = (successPayload) => {
//..
}
const failedCallback = (errorMessage) => {
//..
}
getUserSubscription(successCallback, failedCallback)
return (
// ...
)
}