上一篇:【实例】React 组件传值方法: Props、回调函数、Context、路由传参
MobX
MobX 是一个状态管理库,它提供了一种响应式的数据流方案,使得状态的变化能够自动地反映到相关的组件中。
MobX 的核心理念是可观察的状态(Observable State)和响应式行为(Reactive Behavior)。将状态标记为可观察的后,MobX 可以自动跟踪状态的变化,并且在状态发生变化时自动通知相关的组件进行更新。
概念
-
State(状态)
状态 是驱动应用的数据。通常有像待办事项列表这样的业务数据状态,还有像当前已选元素的视图状态。 -
action(动作)
动作 是改变状态的代码。用户事件、后端数据推送、预定事件、等等。
在 MobX 中可以显式地定义动作,它可以帮你把代码组织的更清晰。如果是在严格模式下使用 MobX 的话,MobX 会强制只有在动作之中才可以修改状态。 -
Derivations(衍生)
任何源自状态并且不会再有任何进一步的相互作用的东西就是衍生。MobX 区分了两种类型的衍生:
Computed values(计算值): 它们是永远可以使用纯函数从当前可观察状态中衍生出的值。黄金法则: 如果你想创建一个基于当前状态的值时,请使用 computed。(所有的计算值都应该是纯净的。它们不应该用来改变状态)
Reactions(反应): Reactions 是当状态改变时需要自动发生的副作用。
原则
MobX 支持单向数据流,也就是动作改变状态,而状态的改变会更新所有受影响的视图。
例子
MobX 将一个应用变成响应式的可归纳为以下三个步骤:
- 定义状态并使其可观察
可以用任何你喜欢的数据结构来存储状态,如对象、数组、类。循环数据结构、引用都可以。只要确保所有会随时间流逝而改变的属性打上 mobx 的标记使它们变得可观察即可。
import {observable} from 'mobx';
var appState = observable({
timer: 0
});
- 创建视图以响应状态的变化
用 observer 来定义观察者组件。
import {observer} from 'mobx-react';
@observer
class TimerView extends React.Component {
render() {
return (
<button onClick={this.onReset.bind(this)}>
Seconds passed: {this.props.appState.timer}
</button>
);
}
onReset() {
this.props.appState.resetTimer();
}
};
ReactDOM.render(<TimerView appState={appState} />, document.body);
- 更改状态
只有在严格模式(默认是不启用)下更新被观察的状态才需要 action 包装。 建议使用 action,因为它将帮助你更好地组织应用,并表达出一个函数修改状态的意图。 同时,它还自动应用事务以获得最佳性能。
appState.resetTimer = action(function reset() {
appState.timer = 0;
});
setInterval(action(function tick() {
appState.timer += 1;
}), 1000);
Redux
在 Redux 中,所有的状态被保存在 store 状态树中(一个应用程序中只能有一个)。任何组件都可以直接从 store 中访问特定对象的状态。如果要更改状态,需要分发一个 action,分发在这里意味着将可执行信息发送到 store,然后 store 将 action 代理给相关的 reducer。reducer是一个纯函数,它可以查看之前的状态,执行一个 action 并且返回一个新的状态。
例子
App.js 是应用程序的入口文件。使用 Provider 组件包裹整个应用程序,并传递 Redux store 作为属性。这样,应用程序中的所有组件都能够访问 Redux store 中的状态和动作。
// src/App.js
import React from 'react';
import Counter from './components/Counter';
import { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<div>
<h1>React Redux Counter App</h1>
<Counter />
</div>
</Provider>
);
}
export default App;
在组件里使用 useSelector 钩子从 Redux store 中获取状态,并使用 useDispatch 钩子获取 dispatch 函数用于分发动作。
// src/components/Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from '../actions';
function Counter() {
const counter = useSelector(state => state);
const dispatch = useDispatch();
return (
<div>
<h1>Counter: {counter}</h1>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
}
export default Counter;
action 文件定义了两个动作创建函数 increment 和 decrement。这些动作创建函数用于创建描述动作的对象,并且这些对象包含一个 type 属性,指示要执行的动作类型。然后定义 reducer,Reducer 函数接收两个参数:当前状态(state)和要执行的动作(action)。根据不同的动作类型,它会返回一个新的状态。创建 redux store,将 reducer 作为参数传进去。
// src/actions/index.js
export const increment = () => {
return {
type: 'INCREMENT'
};
};
export const decrement = () => {
return {
type: 'DECREMENT'
};
};
// src/reducers/index.js
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
};
export default counterReducer;
// src/store/index.js
import { createStore } from 'redux';
import counterReducer from '../reducers';
const store = createStore(counterReducer);
export default store;
对比
Redux 强调不可变性和可预测性,而 MobX 更灵活,也少很多模版代码,状态的自动追踪和更新也使开发更方便。但是优点也同时可能是缺点,太灵活对于讲究严格的大型应用可能会有问题。但是私以为只要组织的好,规范代码结构,用 MobX 也挺严谨的。
一张很多地方看到的对比图