saga-resource
v0.3.87
Published
saga-resource
Downloads
414
Readme
saga-resource
Write your store in one place, without boilerplates
Features:
- Easy to implement on your current redux + redux-saga architecture
The initial setup
Make your resource
// ./store/counter.ts
import {delay, put} from 'redux-saga/effects';
import {makeResource} from 'saga-resource';
interface CounterState {
count: number;
}
interface CounterReducers {
inc: (num?:number) => CounterState;
}
interface CounterEffects {
asyncInc: (num?:number) => any;
}
const counter = makeResource<CounterState, CounterReducers, CounterEffects>({
name: 'counter',
state: {
count: 0,
},
reducers: {
inc: (num=1, {state}) => {
return {...state, ...{count: state.count + num}};
},
},
effects: {
*asyncInc(num=1): any {
yield delay(500);
yield put(counter.actions.inc(num));
},
},
});
export default counter;
Make your store
// ./store/index.ts
import {combineResources} from 'saga-resource'
import counter from './counter'
const combinedResources = combineResources({counter})
const rootReducer = combinedResources.combineReducers()
const rootSaga = combinedResources.getSaga()
export type AppState = ReturnType<typeof rootReducer>
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, bindMiddleware(sagaMiddleware))
sagaMiddleware.run(rootSaga)
export default store
You are all setup, let's dispatch resource actions from your component.
// ./YourComponent.jsx
import counter from 'store/counter';
// ...
const mapDispatchToProps = (dispatch) => {
return {
add5: dispatch(counter.actions.inc(5))
asyncAdd: dispatch(counter.actions.asyncInc())
}
}
// ...
actions will be generated by reducers and effects you defined.
yield saga-resource effect from your saga file.
// ./YourSagaFile.js
import counter from 'store/counter';
// ...
function* asyncAdd5(){
try {
yield counter.effects.asyncInc(5)
}
}
// ...
Built-in reducers
There are 3 built in reducers, set, update, clear
set
will overwrite your state e.g. dispatch(resource.actions.set(newState))
update
will set the key with the payload, the key can be a path, e.g. update your key 'a.b.c with data' dispatch(resource.actions.update('a.b.c', data))
clear
clear will reset your state to it's initial state. e.g. dispatch(resource.actions.clear())
Built-in effects
There are 4 built-in effects, createRequest, updateRequest, fetchRequest, deleteRequest
, these four effects will send request corresponds to post, patch, get, delete
, with an exception that fetchRequest
will set your state based on data the request returns.
You can call these methods only if you have a path
setup in your resource definition.
For example:
// ./store/user.ts
import {makeResource} from 'saga-resource';
export interface UserState {
username: string;
}
const user = makeResource<UserState, {}, {}>({
name: 'user',
path: 'http://localhost:8080/user',
state: {
username: 'Uninitialized user',
},
});
export default user;
Fetch user by dispatch(user.actions.fetchRequest())
Or you can use effect directly in you saga file yield user.effects.fetchRequest()
Loading status
All effects will have loading status stored in resourceState.meta.loading
Error handling
When ever resource effects throws an error, { type: SagaResource.actionTypes.ERROR
, data } will be dispatched.