redux-resource-factory
v0.0.3
Published
Handle resources like a boss.
Downloads
2
Readme
redux-resource-factory
Handle resources like a boss 😎.
redux-resource-factory
provides useful abstraction over redux-managed resources that:
- are (typically) asynchronous
- succeed / fail
- might get cancelled / reset
Usage:
import { createStore } from "redux";
import { createResource } from "redux-resource-factory";
const { reducer, request, success } = createResource<User[], string>("USERS");
const store = createStore(reducer);
type AppState = ReturnType<typeof reducer>; // Resource<User[], string>
store.getState(); // { data: null, error: null, loading: false }
store.dispatch(request());
store.getState(); // { data: null, error: null, loading: true }
store.dispatch(success({ data: [] }));
store.getState(); // { data: [], error: null, loading: false }
API
Resource<T, E>
Represents a resource of type T
that can fail with an error of type E
.
type Resource<T, E> = {
data: T | null;
error: E | null;
loading: boolean;
};
resource(init?)
Used to create instances of Resource
.
Arguments:
init?: Partial<Resource<T, E>>
- overrides (default values used otherwise)
Returns:
Resource<T, E>
The default values are:
{
data: null,
error: null,
loading: false,
}
createResource(tag, options?)
Used to create a reducer for managing the particular resource, along with corresponding action creators.
Arguments:
tag: string
- a unique string identifier of a resource (used internally to filter corresponding actions)options?: { initialState?: Resource<T, E> }
- additional options (currently only include specifying initial state)
Returns:
{ reducer, ...actionCreators }
where reducer
has the following signature:
(
state: Resource<T, E> | undefined,
action: ReturnType<typeof actionCreators[keyof typeof actionCreators]>
) => Resource<T, E>;
and the actionCreators
are:
request()
{
data: null,
error: null,
- loading: false,
+ loading: true,
}
success(payload: { data: T })
{
- data: null,
+ data: [{...}, {...}],
error: null,
- loading: true,
+ loading: false,
}
error(payload: { data: E })
{
data: null,
- error: null,
+ error: "Unauthorized",
- loading: true,
+ loading: false,
}
reset()
{
- data: [{...}, {...}],
+ data: null,
error: null,
loading: false,
}
cancel()
{
data: null,
error: null,
- loading: true,
+ loading: false,
}
Examples
With redux-thunk
export const fetchUser = (
userId: User["id"],
cancel: Deferred<void>
): ThunkAction<Promise<void>, AppState, any, AnyAction> => async dispatch => {
dispatch(request());
try {
const { data } = await axios.get(
`/users/${userId}`,
{
cancelToken: new CancelToken(c => cancelDefer.promise.then(() => c())),
}
);
dispatch(
success({ data })
);
} catch (err) {
dispatch(
isCancel(err)
? cancel()
: error({ data: err })
);
}
};
With redux-saga
function* fetchUserSaga(action: SomeAction) {
const source = axios.CancelToken.source();
yield put(request());
try {
const { data } = yield call(
axios.get,
`/users/${action.payload.userId}`,
{ cancelToken: source.token },
);
yield put(success({ data }));
} catch (err) {
yield put(error({ data: err }));
} finally {
if (yield cancelled()) {
yield put(cancel());
source.cancel();
}
}
}