为什么会考虑使用状态管理?
项目开发中经常会碰到以下场景: 1.业务系统许多接口,入参都需要传递登陆人 id
1
| userCode: localStorage.getItem('userCode'),
|
2.业务系统选择下拉框,如城市,销售业务员、车型、折旧选项等均为同一接口数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| getDrivers(name) { http .get("/api/Common/GetDrivers", { Key: name }) .then(res => { const { success, result } = res.data; if (success) { if (Array.isArray(result)) { this.setState({ drivers: result }); } else { this.setState({ drivers: [] }); } } else { message.error("获取司机信息失败"); } }) .catch(err => { console.error(err); }); }
|
3.兄弟组件传值等
MobX 背后的哲学
任何可以从应用程序的状态中获取/衍生的数据都应该可以自动被获取/衍生。
MobX 遵循单项数据流,通过 action 改变 state(可观测对象),state 的变化又会触发 computed value 和 reaction 的重新执行。
Redux 和 Mobx 相同点
1.优秀的状态管理解决方案 2.采用单向数据流管理状态 3.Action-->State-->Views
Mobx 和 Redux 的区别
| Mobx |
Redux |
| 多个 store 对象,多 store 间的数据共享、相互引用 |
单一数据源,应用共享一个 store 对象 |
| state 结构可以任意嵌套 |
state 结构尽可能的扁平化,从而减少嵌套层级 |
| state 可观测,可以直接修改 |
普通 JavaScript 对象存储 state |
| 上手成本低、开发效率高 |
需要熟悉函数式编程基础 |
| 代码量更少 |
需要写更多的代码来执行严格的规范 |
选择
| MobX |
Redux |
| 相对简单的应用 |
复杂度较高的应用 |
MobX 包含的主要概念
- state(状态)
- computed value(计算值)
- reaction(响应)
- computed value 和 reaction 会自动根据 state 的改变做最小化的更新
- action(动作)
Mobx 的缺点
如使用装饰器时团队如果不制定一个规范,后期可能难以维护。
解决方案
自定义装饰器还是要在项目组内达成共识才行。
如:将各个状态封装到一个对象中导出(防止代码难以维护,加入静态图和 gif 图)

将使用 Mobx 观测的数据整合到一个 stores 对象注入到 Provider
到‘src/stores/index.js’中
获取可观测的 state
通过 React-mobx 提供 Provider 组件在根目录 index.jsx 中让容器组件拿到 state
1 2 3 4 5 6 7
| import { Provider } from "mobx-react"; import stores from "./stores"; ... <Provider {...stores}> <App /> </Provider>, document.getElementById('root')
|
Provider 在根组件外包了一层,来让 App 的所有子组件就默认都可以拿到 state。
Provider 源码
只有先获取到 state,在对应组件中才能使用 inject 注入
@inject 注入使用的 Store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { observer, inject } from 'mobx-react'; import { observable } from 'mobx'; @observer @inject('store') class App extends Component { render() { const { store } = this.props; return ( <div> <ul> {store.map((todo) => ( <TodoView todo={todo} key={todo.id} /> ))} </ul> </div> ); } } const TodoView = observer(({ todo }) => { return <li>{todo.title}</li>; });
|
配置装饰器语法
项目中会大量使用到装饰器语法@observable,所以要提前配置装饰器
配置方案
记得配置 jsconfig
computed value 的使用


一般通过computed和@computed创建computed value
1 2
| computed(() => expression) @computed get classProperty() { return expression; }
|
action 的使用
常见的用法
1 2
| action(fn) @action classMethod
|

action.bound 解决 this 指向问题
箭头函数
1 2 3 4 5 6 7
| logout = () => { this.userId = undefined; this.username = 'jack'; this.password = '123456'; sessionStorage.removeItem('userId'); sessionStorage.removeItem('username'); };
|
action.bound/@action.bound
1 2 3 4 5 6 7
| @action.bound logout() { this.userId = undefined; this.username = 'jack'; this.password = '123456'; sessionStorage.removeItem("userId"); sessionStorage.removeItem("username"); }
|
1 2 3 4 5 6 7 8 9 10 11 12
| { authStore.userId && authStore.userId.length > 0 ? ( <span className='user'> 当前用户:{authStore.username} <button onClick={authStore.logout}>注销</button> </span> ) : ( <span className='right-link'> <Link to={{ pathname: '/login', state: { from: location } }}>登录</Link> </span> ); }
|
mobx 调试工具
mobx-react-devtools 是一个用于调试 MobX+React 项目的工具,可以追踪组件的渲染以及组件依赖的可观测数据。
安装
只需要在开发环境下使用调试工具,安装命令使用的参数是–save-dev
1 2 3
| npm install mobx-react-devtools --save-dev 或 yarn add mobx-react-devtools --save-dev
|
再次运行程序,界面右上角会多出三个小图标,是 mobx-react-devtools 的功能键。
使用
点击第一个图标,当组件发生渲染行为时,对应的组件会被高亮显示

- 高亮组件右上角显示的 3 个数字分别代表截至当前组件渲染的次数、组件 render 方法执行的时间、组件从 render 方法开始到渲染到浏览器界面使用的时间

点击第二个图标后,再用鼠标选择任意一个组件,可以查看该组件会对哪些数据的变化做出响应

点击第三个图标,控制台会输出发生的 action、响应的 reaction 等调试日志信息

当然你也可以使用 trace 进行调试
参考