前端学习笔记-RxJS与Redux-Observable (二)

438 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

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》