Redux和TypeScript参考官网即可。Rxjs作为一个反应式编程思想的JS实现库,在前端这种多交互、多请求的环境下,很适合使用。同时,Redex与Rxjs的结合redux-observable,也能解决异步Action的问题。个人认为,Rxjs在解决复杂交互、数据流处理这些方面都是非常合适的,当然,因为学习曲线相对比较复杂、且需要转变思想,运用的比较少。Rxjs的介绍与使用在本篇就不介绍了,本文重点介绍这几个库在React中的结合使用,以及一些注意点。
本文以redux-observable官方的一个示例为基础
一、准备
1、 相关库:
2、相关目录结构:
-src
-store
-epics
counter.ts // 存放所有counter相关的epic
index.ts // 收集所有epic并合并,对外暴露
-actions
index.ts // 收集所有action并合并,对外暴露
-reducers
counter.ts // 存放所有counter相关的reducers
index.ts // 收集所有reducer并合并,对外暴露
index.ts // 处理所有redux相关,并对外暴露
types.ts // 定义store相关type
二、定义相关类型
// types.ts
import { ActionType } from 'typesafe-actions';
import * as actions from 'store/actions';
export interface RootState { // 定义根数据类型
counter: number;
}
export const INCREMENT = 'INCREMENT'; // 定义一个Reducre的Type
export const INCREMENT_IF_ODD = 'INCREMENT_IF_ODD'; // 定义一个Reducre的Type
export type Action = ActionType<typeof actions>; // 定义所有Action的类型、使用ActionType从actions里面获取
三、定义Action
因为我们在types.ts先把所有Action定义了,所以我们可以先定义action.
import { action, createAction } from 'typesafe-actions';
import { INCREMENT, INCREMENT_IF_ODD } from '../types';
export const incrementCounter = () => action(INCREMENT);
export const incrementOddCounter = createAction(INCREMENT_IF_ODD)();
createAction与action作用是一致的,createAction功能上更多一点,具体可以官网查看。
四、定义Reducer
和常规的Reducer没什么区别,当然可以使用typesafe-actions的createReducer创建更复杂、功能更全的。
// counter.ts
import {
INCREMENT,
Action,
} from '../types';
const initState: number = 0;
const counter = (state = initState, action: Action): number => {
switch (action.type) {
case INCREMENT:
return state + 1;
default:
return state;
}
};
export default counter;
需要注意的是,当action中带入数据传入的时,action中的数据会被redux-observable包装了一层,在action.payload
下,这点取值时需要注意。
五、定义Epic
import { map, filter } from 'rxjs/operators';
import { ofType } from 'redux-observable';
import { Epic } from 'redux-observable';
import { incrementCounter, incrementOddCounter } from 'store/actions';
import { RootState } from '../types';
import { Action, INCREMENT_IF_ODD } from '../types';
console.log(incrementOddCounter);
const incrementIfOddEpic: Epic<Action, Action, RootState> = (action$, state$) => action$.pipe(
ofType(INCREMENT_IF_ODD), // 所有的Action都会触发Epic,为了获取指定的,我们需要先过滤。
filter(() => state$.value.counter % 2 === 1), // 过滤掉使counter不为奇数的INCREMENT_IF_ODD,
map(() => incrementCounter()) // 最终映射到INCREMENT的action。
);
export default [incrementIfOddEpic];
六、结尾
reducer、action、reducer都创建完成之后就是一些连接的工作,基本无异。本文仅是简单的一个介绍,上面的epic中,我们未使用异步操作,我们可以在ofType之后执行异步操作,如:
pipe(
ofType(FETCH_REMOTE),
switchMap(action => from(fetch('/api/user')).pipe(
map(getUser) // getUser是action
))
)
通过switchMap把数据流最终写入到getUser相关的state。这样的流操作是不是方便很多。Rxjs还有更多的操作。 自己写的一个简单示例已经上传到github,同时还有一个很好的参考项目提供给大家。