关于 Redux
个人认为,一些轻量级的项目是完全用不到 Redux。
简单的单例出一个全局变量管理器,就可以满足项目的需要。
不过如果项目一旦沉重起来,需求逻辑繁琐,父子组件通讯错综复杂,
开发人员思路又不统一,
这个时候如果只是使用全局变量管理,
那么数据随时都可能被更改,全局变量将会成为一团乱麻,变得不可被信任。
项目的迭代和维护成本也将会迎来指数级的上升,
如果这个时候能有一个全局的对象,
可随时被观察状态,只能用特殊方式修改状态,
将会对项目的维护非常有帮助。
而这也就是 Redux。
官方文档
Taro 的 Redux 官方文档
Redux 数据流程图
借用网上流传的图片,发现有个箭头的遗漏,
一切起源是因为组件触发了 action,
才引发了这一系列的流程。
使用流程
- 准备好仓库 state。(只操作一次,聚合所有数据)
1 2 3 4 5 6 7 8 9 10 11
| import { createStore, applyMiddleware } from "redux"; import thunkMiddleware from "redux-thunk"; import { createLogger } from "redux-logger"; import rootReducer from "../reducers";
const middlewares = [thunkMiddleware, createLogger()];
export default function configStore() { const store = createStore(rootReducer, applyMiddleware(...middlewares)); return store; }
|
- 准备一个数据对象。
举个例子,我准备将主页的相关信息都存储在仓库的这个对象里 MainPageInfo。
所以我会创建 3 个文件。
1 2 3
| ../actions/MainPageInfo.ts ../constants/MainPageInfo.ts ../reducers/MainPageInfo.ts
|
- 准备好对这个对象操作的指令代号。
我会将指令代号以及类型声明存放在这个文件中。
../actions/MainPageInfo.ts
1 2 3 4 5
| export const SET_MAIN_PAGE_SELECT: string = "SET_MAIN_PAGE_SELECT"; export type MainPageInfoType = { nSelectIndex: number; };
|
- 准备对这个对象的行动。
我会将所需要的操作存放在这个文件中。
../actions/MainPageInfo.ts
1 2 3 4 5 6 7 8 9 10 11 12
| import { SET_MAIN_PAGE_SELECT } from "@/constants/MainPageInfo";
export function setMainPageSelect(nSelectIndex: number) { return { type: SET_MAIN_PAGE_SELECT, nMainPageSelect: nSelectIndex, }; }
export default { setMainPageSelect, };
|
- 准备对这个对象数据的改动。
我会将操作之后的数据改动放在这个文件中。
../reducers/MainPageInfo.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { SET_MAIN_PAGE_SELECT } from "@/constants/MainPageInfo";
const INITIVAL_STATE = { nSelectIndex: 0, };
export default function MainPageInfo(state = INITIVAL_STATE, action) { switch (action.type) { case SET_MAIN_PAGE_SELECT: return { ...state, nSelectIndex: action.nMainPageSelect, }; default: return { ...state, }; } }
|
- 准备阶段完毕
那么准备阶段完毕,
我可以通过 setMainPageSelect 方法传入的参数,
来修改 store.MainPageInfo.nSelectIndex
而此时我的期望数据结构就会是这样。
1 2 3 4 5
| store = { MainPageInfo: { nSelectIndex: number, }, };
|
- 在 Taro 中运用
其实 TS 近乎强迫症的语法,在这一步折腾了好久,不断的在语法错误提示中挣扎。
在参考了多方资料之后,总算摸索出来一套不再错误提示的写法。
示例是用最基本的方法来操作 Redux。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import { connect } from '@tarojs/redux'; import { MainPageInfoType } from '@/constants/MainPageInfo'; import { setMainPageSelect, } from '@/actions/MainPageInfo';
// 类型声明:传递过来的变量 type PageStateProps = { MainPageInfo: MainPageInfoType; };
// 类型声明:传递过来的dispatch方法 type PageDispatchProps = { setMainPageSelect: (nSelectIndex: number) => any; };
// 类型声明:传递过来的普通方法 type PageOwnProps = { };
// 类型声明:组件内变量 type PageState = { };
type IProps = PageStateProps & PageDispatchProps & PageOwnProps;
type IState = PageState;
@connect( ({ MainPageInfo }) => ({ MainPageInfo }), dispatch => ({ setMainPageSelect (nSelectIndex: number) { dispatch(setMainPageSelect(nSelectIndex)); } }) ) export default class Main extends Component<IProps, IState> { // 测试按钮 handleTestClick () { const { MainPageInfo, setMainPageSelect } = this.props; console.log('handleTestClick before.', MainPageInfo); setMainPageSelect(9999); console.log('handleTestClick after.', MainPageInfo); }
// render () { ( // ... ) } }
|
我们不能直接的去修改 store 中的数据,
我们可以触发 handleTestClick,
通过 dispatch,调用 setMainPageSelect 方法,
来对 store.MainPageInfo.nSelectIndex 的数值进行修改。
后记
前端的框架语法更新很快,
React 16.8 版本新增了 React Hook 的写法。
这也让操作 Redux 的方式更加灵活了。
我会在接下来的时间里研究一下 Hook 的写法,整理出来。