create-async-slice
v1.2.9
Published
## Helper for creating async slices with redux toolkit to avoid boilerplates
Downloads
69
Maintainers
Readme
Create async slice
Helper for creating async slices with redux toolkit to avoid boilerplates
API
createAsyncSlice
Returns redux-toolit slice object with 4 actions:
request
- to dispatch request with payload for fetching data and set isProcessing:true
success
- to fulfill your store with success data from APIerror
- to fulfill data with error from API responsereset
- to reset store's state
createAsyncMappingSlice
Stands for creating relations between async states or for making complicated async lists slices. Example: you're users are toggleable sections and when you toggle each section - you need to load company info for that certain user. So there's multiple loading companies for each opened user at the same time
Returns redux-toolit slice object with 4 actions:
request
- to dispatch request with payload for fetching data and set isProcessing:true
Expects{ id }
as default.id
is id of item in list which needs to get additional data e.g. company user id.success
- to fulfill your store with success data from API. Expects{ id, value }
as default.value
is your data you want put into your redux storeerror
- to fulfill data with error from API response. Expects{ id, error }
as default.reset
- to reset store's state. Expects{ id }
as default.
How does async slice's state look like?
// state.users
// createAsyncSlice:
{
getUsers: {
value: [{ name: 'Test user', id: 'user-id-1' }],
isSuccess: true,
isProcessing: false,
error: null
}
}
// createAsyncMappingSlice:
{
getUserCompanies: {
['user-id-1']: {
value: [{ name: 'Test Company', id: 'company-id-1' }],
isSuccess: true,
isProcessing: false,
error: null
}
}
}
Usage
src/ducks/users/users.slices.ts
import { combineReducers } from 'redux';
import { createAsyncSlice } from 'create-async-slice';
export const getUsersSlice = createAsyncSlice<RequestPayload, SuccessPayload, ErrorPayload>({
name: 'getUsers',
selectAsyncState: (state) => state.users.getUsers // To get `getUsersSlice.selectors` work
});
/* RequestPayloadWithId, SuccessPayloadWithId, ErrorPayloadWithId:
these are optional since we always should pass an id of parent list by default
*/
export const getUserCompaniesSlice = createAsyncMappingSlice<RequestPayloadWithId, SuccessPayloadWithId, ErrorPayloadWithId>({
name: 'getCompaiesByUserId',
selectAsyncState: (state) => state.users.getCompaiesByUserId // To get `getUserCompaniesSlice.selectors` work
})
export const usersReducer = combineReducers({
getUsers: getUsersSlice.reducer,
getUserCompanies: getUserCompaniesSlice.reducer
});
src/ducks/users/users.sagas.ts
function* getUserCompaniesSaga({ payload }) {
// id - companyId
const { id } = payload;
try {
const { data } = yield call(usersApi.getUserCompanies, id);
yield put(getUserCompaniesSlice.actions.success(data));
} catch (e) {
yield put(getUserCompaniesSlice.actions.error(e.message));
}
}
function* getUsersSaga() {
try {
const { data } = yield call(usersApi.getUsers);
yield put(getUsersSlice.actions.success(data));
} catch (e) {
yield put(getUsersSlice.actions.error(e.message));
}
}
export function* usersSagas() {
yield takeAll(getUsersSlice.actions.request, getUsersSaga);
yield takeAll(getUserCompaniesSlice.actions.request, getUserCompaniesSaga);
}
src/store/reducers.ts
import { usersReducer } from '@ducks/users/users.slices';
export const reducers = {
users: usersReducer,
};
src/components/Users.ts
import React, { useSelector, useDispatch, useEffect } from 'react';
import { getUsersSlice } from '@ducks/users/users.slice';
import { selectIsGetUsersProcessing, selectGetUsersData } from '@ducks/users/users.selectors';
export const Users = () => {
const dispatch = useDispatch();
const isProcessing = useSelector(getUsersSlice.selectors?.isProcessing);
const usersData = useSelector(getUsersSlice.selectors?.value)
useEffect(() => {
dispatch(getUsersSlice.actions.request());
}, []);
return (
<div>
{usersData.map(user => (
<User {...user}>
))}
</div>
)
}
src/components/User.ts
import React, { useSelector, useDispatch, useEffect } from 'react';
import { getUserCompaniesSlice } from '@ducks/users/users.slice';
import { selectIsGetUserCompanyProcessing, selectGetUserCompaniesByIdData } from '@ducks/users/users.selectors';
export const User = ({ id, name }) => {
const dispatch = useDispatch();
const isProcessing = useSelector(state => getUserCompaniesSlice.selectors?.isProcessing(state, { id }));
const companiesData = useSelector(state => getUserCompaniesSlice.selectors?.value(state, { id }));
useEffect(() => {
dispatch(getUserCompaniesSlice.actions.request({ id }));
}, [id]);
return (
<div>
{companiesData.map(company => (
<Company {...company}>
))}
</div>
)
}
API
Async Slice Options:
createAsyncSlice
accepts all createSlice
options and following:
| Option key | Description | Default Value |
| ------------- | ------------- | ------------- |
| selectAsyncState
| (state) => AsyncState
, optional
. Redux selector which returns your async slice state (needed for using createAsyncSlice({ ... }).selectors
). E.g: selectAsyncState
: (state) => state.users.getUsers
|
createAsyncMappingsSlice
accepts all createAsyncSlice
options and following:
| Option key | Description | Default Value |
| ------------- | ------------- | ------------- |
| mappingsAmountLimit
| number
, optional
. Limits max amount of items stored in slices state (to avoid memory leak) | undefined
|