本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Redux-Observable
基于RxJS的Redux中间件。
在过去的Redux中,每当一个action被派发,它就会经过所有的reducer函数,并返回一个新的state。而Redux-observable接收所有这些被派发的action和新state,并从中创建两个Observable对象:Actions observable action$和States observable state$。
Actions observable将发射所有使用store.dispatch()分配的动作。States observable将发射所有由root reducer返回的新状态对象。
这些概念看不懂没关系,只需要理解和编写Epic就能使用Redux-observable:
Epic
Epics是一个函数,它接受一个actions 流,以及一个可选的state流并返回一个actions 流。
function (action$: Observable, state$: StateObservable): Observable;
actions in, actions out:我们发送完action,在reducers接收到action之后, Epics函数会监听并接收到这个action。换句话说,一个action会在我们dispatch后,经过reduce最终进入Epics。而且因为Ecpis是action out,所以在Ecpis做完事情之后,可以再发送新的action回到reducer。
当然,"做完事情"可以指异步请求到了数据,而后发送新的action时,把请求到的数据塞进新action的payload,此时我们就完成了经典的异步Action场景。
const pingEpic = action$ => action$.pipe(
ofType('PING'),
flatMap(action => ajax('https://example.com/pinger')),
mapTo({ type: 'PONG' })
)
/*注*/ ofType(TYPE); /*--等同于->*/ filter((action) => action.type === TYPE);
创建好多个epic之后就可以按如下方式应用EpicMiddleware与Redux结合了:
const rootReducer = combineReducers({ aReducer, bReducer })
const epicMiddleware = createEpicMiddleware();
const rootEpic = combineEpics(aEpic, bEpic, cEpic)
const store = createStore(rootReducer, initialState, applyMiddleware(epicMiddleware))
epicMiddleware.run(rootEpic);
References: www.jianshu.com/p/c1adaa9d8… www.freecodecamp.org/news/beginn… fe.rualc.com/note/rxjs.h… fe.rualc.com/note/redux-…
RxJS与Promise对比(一方能做 但另一方不可做的)
Promise:
- 一旦创建立即执行;
- 有 3 种状态:pending,成功,失败;
- 结果不受其他操作影响,不可取消;
- 当异步操作完成或失败时,Promise会处理一个单个事件。
Observable:
- 创建时不会立即执行(lazy evaluation), 只有当真正需要结果的时候才会去调用它。
- 有 N + 3 个状态(idle、pending、resolved_0~N、completed 和 error)。
- Observable 的订阅允许取消(dispose)
- 不同于promise只能处理单个值,Observable 支持多值甚至是数据流。
RxJS与Redux比较
怕了,准备一下这点,万一以后有懂Redux的面试官从这个角度考我呢
Redux的组件既可以通过dispatch一个action修改状态,又可以调用store的subscribe方法订阅更新,这种状态管理的思路与RxJS的响应式处理相似;
Redux的特点是数据集中在Store中,这其实方便了组件之间的通信;如果用RxJS实现,可能两两组件之间就都需要建立一个Subject对象作为通信桥梁,随着组件数目增加管理起来会十分复杂;
但实际上Redux的最基本功能可以通过RxJS一行模拟:
action$.scan(reducer, initState).subscribe(renderView);
scan操作符非常适合管理状态;
下面贴一个进阶实现,模拟createStore函数,返回dispatch, getState, subscribe
import { Subject } from './rxjs.umd.min.js/Subject'
const createReactiveStore = (reducer, initState) => {
const action$ = new Subject();
let currState = initState;
const store$ = action$.startWith(initState).scan(reducer).do(state => {
currState = state;
});
return {
dispatch: action => { return action$.next(action); },
getState: () => currState,
subscribe: subscriber => {
store$.subscribe(subscriber)
}
}
}
export default createReactiveStore;
Reference:《深入浅出RxJS》