重学 Rxjs —— 实现 redux

356 阅读2分钟

「这是我参与2022首次更文挑战的第37天,活动详情查看:2022首次更文挑战

上一节中我们已经发现了在 react 中使用 Rxjs 和 使用 redux 很像,这一节我们就来尝试一下,使用 Rxjs 来实现一个 redux。

在正式编码之前还是需要回顾一下 redux 相关知识和概念,一个 redux 应用中有 store、reducer 和 action 三个重要概念,我们来一一看一下。

首先是 store,store 是用来存储数据模型的,在 redux 中有一个 store,所有的数据放在 store 中,它的数据只会被 reducer 修改, UI 层可以订阅 store 中的数据信息进行消费。

reducer 的作用是修改 store,它是一个纯函数,接收 state 和 action 作为参数,通过原始的 state 生成一个新的 state。

action 是实际触发 reducer 的行为,每一个 action 可以对应为 reducer 的一个规则,我们在程序中通过 dispatch 可以触发一个 action,每一次 action 会执行一次 reducer 函数,在其中根据对应的 action 会生成一个新的 state,这样实现 state 的变化效果。

我们再来看 Rxjs,在 Rxjs 中我们可以使用 Subject 来充当 action 桥梁,reducer 函数是一个接收前一次值和当前值生成新值的一个过程,在 Rxjs 中 scan 操作符恰好可以满足需求,每一次触发 action 后,通过 scan 执行 reducer,就可以实现 redux 的能力了,完整实现:

const createStore = (reducer, initialState) => {
	const action$ = new Subject();
	let currentState = initialState;
	const store$ = action$.pipe(
		startWith(initialState),
		scan(reducer),
		tap(state => currentState = state),
	)
	return {
		dispatch: (action) => action$.next(action),
		getState: () => currentState,
		subscribe: fn => store$.subscribe(fn),
	}
}

这样就完成了一个 Rxjs 版本的 redux,这个 redux 与原生的 redux 基本是一致的,唯一的区别是 Rxjs 需要有数据订阅才会生效,因此这里一定要确保数据能够即时被订阅处理,而通常我们都是使用 react-redux 库来处理订阅过程,这个库是可以立即订阅的。我们尝试一下把我们的 redux 与 react-redux 库结合使用,它是可以正常工作的,也就是说实际上我们的 Rxjs 版本 redux 是可以骗过 react-redux 以假乱真的。