Sigi framework document
Introduction
Basic
Recipes
FAQ
基本概念
概念ActionDispatcher & ActionsCreatorEffects依赖注入
深入
常见问题

Action

Sigi 的 EffectModule 底层由一个名为 State 的对象实现。State 对象和 ReduxStore 非常类似。它总是接收从 DispatcherEffect 发送过来的 Action, 并且将它们传递给 ReducerEffect

在使用 Sigi 的应用中,你不需要手动创建 Action,所以我们并没有对外提供 Dispatch 方法。取而代之有两种方法可以达到 Dispatch action 的效果:

  • 调用 Dispatcher 上的方法
  • Effect 中发射 (emit) action

Dispatcher & ActionsCreator

Dispatcher 是一个包含丰富类型定义的 ActionsCreator 的抽象。 所有 EffectModule 类上被 Reducer, ImmerReducer, EffectDefineAction 装饰器装饰的方法,都在 EffectModule 类中的 ActionsCreator 对象上有一个对应的方法,也在 Component 中的 Dispatcher 上有一个对应的方法。EffectModule 类中的 ActionsCreator 用来生成一个 Action 并且发射(emit) 给 State 对象,Component 中的 Dispatcher 用来直接 Dispatch 一个 Action 给 State 对象。

Dispatch props created by Redux-Actions

你可能在写 Redux 的时候用过 Redux-Actions 这个库。Sigi 中的 ActionsCreator 概念与 Redux-Actions 库中的 ActionsCreator 非常类似。在 Redux 应用中 ActionsCreator 有几个明显的好处:

  • 避免在程序中编写 魔法字符串
  • (在 TypeScript 应用中)提供类型信息
  • 减少样板代码

下面的例子展示了在 Redux 应用中使用和不使用 Redux-Actions 的区别:

// raw dispatcher
connect(mapStateToProps, (dispatch) => bindActionCreators({
addCount: (count: number) => dispatch({ // losing type information here
type: 'ADD_COUNT',
payload: count,
}),
}, dispatch))
// reducer
export const reducer = (state, action) => { // losing type information here
switch 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 dispatcher
connect(mapStateToProps, (dispatch) =>
bindActionCreators(
{
addCount: ADD_COUNT,
} as DispatchProps,
dispatch
)
);
// reducer
export const reducer = handleActions(
{
[`${ADD_COUNT}`]: (state: StateProps, { payload }: Action<number>) => {
return { ...state, count: state.count + payload };
},
},
{ count: 0 }
);

使用 Sigi 管理 actions

定义 EffectModule

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 };
}
}

可以从上面的代码看到,没有任何魔法字符串,也没有冗余的样板代码 🤯。

使用

对使用 React 开发的应用,我们提供了两个 hooks 来在组件中引用 effect module 里定义的操作。 这两个 hooks 都接收 EffectModule 类型作为参数,并返回 Module 对于的 dispatcher

useModuleuseDispatchers

// 使用 module
import { useDispatchers, useModule } from "@sigi/react";
const SomeComponent = () => {
// 注意:我们不需要担心 dispatcher 的类型。
// Sigi 的类型系统可以保证所有定义在 module 中的 reducers/effects 的类型都能 100% 正确地被推导出来。
const [state, dispatcher] = useModule(SomeModule);
// 如果某个组件不关心 module 的状态变更(即便状态更新了,也不需要重新渲染),可以这么使用:
// const dispatcher = useDispatchers(SomeModule);
const onClickAdd = useCallback(() => {
// ts 会对 payload 进行类型检查
// 也可以直接在这里使用**跳转到定义**类似的编辑器功能!
dispatcher.add(1);
// 下面这行会出现 ts 类型错误
// dispatch.add('string value');
}, [dispatcher]);
return (
<div>
<button onClick={onClickAdd}>add 1</button>
<span>count: {state.count}</span>
</div>
);
};