Action
Sigi EffectModule
was implemented by State
object under the hood. State
object is very similar with redux Store
object. It Dispatch actions to reducers
and effects
, and receive actions from Dispatcher
and Effect
.
In sigi application, you will never need to create an Action
by hand, so we do not expose the Dispatch
function.
In replacement, there are two ways to dispatch action:
- call methods on Dispatcher
- emit actions in Effect
Dispatcher & ActionsCreator
Dispatcher is a high level abstraction for ActionsCreator with well defined type information.
Every method in EffectModule
class decorated by Reducer, ImmerReducer, Effect , DefineAction Decorators
match one property with the same name in ActionsCreator in EffectModule class
, and match one property with the same name in Dispatcher in Component
. The ActionsCreator in EffectModule class
is used for emit action in Effect, and the Dispatcher in Component
is used for Dispatch
actions to State
.
Dispatch props created by Redux-Actions
You may have used Redux-Actions in Redux application. ActionsCreator in sigi is very similar with ActionsCreator in Redux-Actions
.And there are few advantages for create ActionsCreator using Redux-Actions
:
- Avoid Magic string
- Provide type information
- Reduce boilerplate codes
// raw dispatcherconnect(mapStateToProps, (dispatch) => bindActionCreators({addCount: (count: number) => dispatch({ // losing type information heretype: 'ADD_COUNT',payload: count,}),}, dispatch))// reducerexport const reducer = (state, action) => { // losing type information hereswitch action.type:case: 'ADD_COUNT':return { ...state, count: state.count + payload }default:return { count: 0 }}
const ADD_COUNT = createAction<number>("ADD_COUNT");interface DispatchProps {addOne: typeof ADD_COUNT;}interface StateProps {count: number;}// react actions dispatcherconnect(mapStateToProps, (dispatch) =>bindActionCreators({addCount: ADD_COUNT,} as DispatchProps,dispatch));// reducerexport const reducer = handleActions({[`${ADD_COUNT}`]: (state: StateProps, { payload }: Action<number>) => {return { ...state, count: state.count + payload };},},{ count: 0 });
The Sigi way
Definition
import { Module, EffectModule, Reducer } from "@sigi/core";interface State {count: number;}@Module("SomeNamespace")class SomeModule extends EffectModule<State> {defaultState = {count: 0,};@Reducer()add(state: State, count: number) {return { ...state, count: state.count + count };}}
As you can see above, in the definition part of a sigi app, there is no magic action string, no redundant boilerplate 🤯.
Usage
For react APP, we provide two hooks that let you refer actions defined in effect modules. both of them receive a EffectModule class and produce a dispatcher referred to this module.
useModule
and useDispatchers
// use moduleimport { useDispatchers, useModule } from "@sigi/react";const SomeComponent = () => {// note: we don't need to worry about the types of dispatcher.// Sigi's type system will ensure all defined actions/effects are 100% accurate referred in dispatcherconst [state, dispatcher] = useModule(SomeModule);// or, if you don't care about the state changes.// const dispatcher = useDispatchers(SomeModule);const onClickAdd = useCallback(() => {// ts will perform typecheck in the payload part// and you can also perform **Jump to definition** in code editordispatcher.add(1);// ts type error// dispatch.add('string value')}, [dispatcher]);return (<div><button onClick={onClickAdd}>add 1</button><span>count: {state.count}</span></div>);};