本文整顿下近期 redux、mobx 在 react 中的应用比照,大家能够依据集体爱好,正当应用
查看残缺 demo
redux 状态治理
redux 根本应用流程
首先把 redux 的根本应用步骤梳理一下
createStore
创立状态汇合store
,初始化的时候参数是相干的reducer
以及middleware
,上面将具体阐明
import {createStore, combineReducers, applyMiddleware} from "redux";
// 初始化状态汇合
const store = createStore(
// 合并 reducer
combineReducers({counter: counterReducer, other: otherReducer}),
// 引入中间件
applyMiddleware(logger)
);
react-redux
中的Provider
组件接管创立的store
,并置于组件顶层
import {render} from "react-dom";
import {Provider} from "react-redux";
render(<Provider store={store}>
<App />
</Provider>,
document.getElementById("app")
);
- 定义
reducer
自定义行为与解决的state
// 初始 state
const INITIAL_STATE = {step: 0,};
// 抽离对外裸露的行为枚举
export const counterActionEnum = {
step: "step",
reset: "reset",
};
// 定义 reducer 不同行为下的不同 state 解决
export default function counterReducer(state = INITIAL_STATE, action) {console.log("reducer@", state, action, INITIAL_STATE);
switch (action.type) {
case counterActionEnum.step:
return {step: state.step + 1,};
case counterActionEnum.reset:
return {...INITIAL_STATE,};
default:
return state;
}
}
connect
链接reducer
参加业务连接,裸露store
与dispatch
到相干业务组件中
import React from "react";
import {connect} from "react-redux";
import {counterActionEnum} from "../reducers/counter";
function Counter(props) {const { counter, doStep, doReset} = props;
return (
<div>
<span> 计步器:{counter.step}</span>
<button onClick={() => doStep()}> 计步 </button>
<button onClick={() => doReset()}> 重置 </button>
</div>
);
}
// 链接 reducer 与 Counter
export default connect(
// mapStateToProps 将 state 映射到组件的 props 中
(state) => ({counter: state.counter}),
// mapDispatchToProps 将 dispatch 转发后的 action 映射到组件的 props 中
(dispatch) => ({
// 通过 dispatch 触发行为
doStep: () => dispatch({ type: counterActionEnum.step}),
doReset: () => dispatch({ type: counterActionEnum.reset}),
})
)(Counter);
redux 数据流
下图能够形象的阐明 redux 在数据中的流程体现:
connect -> Component -> dispatch action -> store -> mapStateToProps -> Component update
引入 redux 中间件
这里思考下 redux 中间件的意义:
- 为什么须要有中间件机制?
- 中间件具体在数据流中如何体现?
- 中间件有哪些利用场景?
自定义中间件
这里咱们先手写一下中间件看看它具体处于数据流的哪一步?
// 自定义中间件规定
const logger = ({dispatch, getState}) => (next) => (action) => {console.log("[logger before]:", action);
// 执行下一个 dispatch
const result = next(action);
console.log("[logger after]:", action, getState());
return result;
};
// ...
// 初始化 store 时引入 logger middleware
const store = createStore(
// 合并 reducer
combineReducers({counter: counterReducer, other: otherReducer}),
// 引入中间件
applyMiddleware(logger)
);
引入中间件后执行一个 action 的打印后果如下:
[logger before]: {type: "step"}
// dispatch action
reducer@ {step: 0} {type: "step"} {step: 0}
[logger after]: {type: "step"} {counter: {…}}
以上打印能够看出 middleware 的能够劫持
dispatch action
向下执行,以此能够看出中间件的重大作用,能够交叉于action
数据流走向:
- 比方我想在每次
dispatch action
前后做些什么;- 比方我又想劫持某些
action
做些什么,这个时候也比拟不便;- 再比方我想实现异步的
action
也能够在这一步去做劫持;由此可见,
redux middleware
意义重大
redux 异步 action
- 咱们看一下 redux-thunk 的源码,通过劫持 action 来扩大异步
其实 redux-thunk 的思路比较简单,劫持了 action function 的扩大
function createThunkMiddleware(extraArgument) {return ({ dispatch, getState}) => (next) => (action) => {
// 劫持 action,对 action 提供了扩大,在扩大中本人去实现异步
if (typeof action === "function") {return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
- 简略来说,其实通过
mapDispatchToProps
中本人异步执行dispatch
即可
function mapDispatchToProps(dispatch) {
return {
// 通过 dispatch 触发行为
doStep: () => {
// 1s 后执行 action
setTimeout(() => {dispatch({ type: counterActionEnum.step});
}, 1000);
},
doReset: () => dispatch({ type: counterActionEnum.reset}),
};
}
mobx 状态治理
mobx 根本应用流程
- 创立一个 store
定义一个 class,应用注解
@observable
使值可响应,应用@action
定义响应办法
import {observable, action} from "mobx";
class CounterStore {
@observable step = 0;
@action
doStep = () => {this.step++;};
@action
doReset = () => {this.step = 0;};
}
// 抛出一个实例
export default new CounterStore();
Provider
引入counterStore
所有的 store 都在顶层通过 Provider 混入到全局
<Provider counterStore={counterStore}>
<div>
<h1>mobx 计步器 </h1>
<CounterApp />
</div>
</Provider>
inject
将须要的状态混入到组件的 props,并通过observer
使组件可响应
// 将 counterStore 混入到 Counter 的 props 中
const CounterApp = inject("counterStore")(observer(Counter));
- 组件中调用对应的 state 与 action
function Counter({counterStore}) {const { step, doStep, doReset} = counterStore;
return (
<div>
<span> 计步器:{step}</span>
{" "}
<button onClick={() => doStep()}> 计步 </button>
{" "}
<button onClick={() => doReset()}> 重置 </button>
</div>
);
}
mobx 数据流
mobx 的思路比较简单,通过 action -> state -> view,下图明确提现了 mobx 的数据交互流程
总结
redux 长处
- 流程标准,依照官网举荐的标准和联合团队格调打造一套属于本人的流程。
- 函数式编程,在
reducer
中,承受输出,而后输入,不会有副作用产生,幂等性。 - 可追踪性,很容易追踪产生 BUG 的起因。
redux 毛病
- 晦涩太繁琐,须要写各种 type、action、reducer,不易上手,初学者可能会感觉比拟绕。
- 同步数据流,异步须要援用其余库(redux-thunk/redux-saga 等)或者通过异步 dispatch 的技巧。
mobx 长处
- 容易上手,class 中治理 state、action,应用简略,基于 Proxy 实现的数据响应式。
- 写更少的代码,实现更多的事。不会跟 redux 一样写十分多的 action、type。
- 使组件更加颗粒化拆分,并且业务更加容易形象。
mobx 毛病
- 过于自在,mobx 提供的约定及模版代码很少,如果团队不做一些约定,容易导致团队代码格调不对立。