mobx-react的作用是将react组件转换为对可观察数据的反应。
首先在项目下安装所需依赖:npm i react react-dom prop-types mobx-react -S
(为了编译JSX语法) npm install --save-dev @babel/preset-react
1)将项目中的index.js文件扩展名改为jsx,并修改webpack.config.js中对应的后缀名,以及新装依赖的配置代码。
"presets": [ ["@babel/preset-env",{"useBuiltIns":"entry"}], ["@babel/preset-react"] ]
2)创建两个React组件,并把它们显示到页面上,然后通过mobx来修改状态,进而实现驱动视图。
3)在index.jsx中导入所需的各个组件。
Store类用于存储数据
import { observable,action } from 'mobx'; import React,{ Component } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; class Store { cache = {queue: []} } const store = new Store(); //Bar Foo class Bar extends Component { static propTypes = { queue: PropTypes.array }; render() { const queue = this.props.queue; return <span>{queue.length}</span>; } } class Foo extends Component { static propTypes = { cache: PropTypes.object }; render() { const cache = this.props.cache; return <div><Bar queue={cache.queue} /></div>; } } ReactDOM.render(<Foo cache={store.cache}/>,document.querySelector('#root'));
浏览器页面中显示0,表示编译成功,React项目能够正常运行。
4)为该React程序添加mobx支持
第一步,把Store中的数据转换为可观察数据
class Store { @observable cache = {queue: []} }
如果这时有警告⚠️,是因为因为可观察的数组并不是真正的数组,从mobx-react中引入PropTypes即可,为了避免与react官方提供的PropTypes重名,将mobx-react中的PropTypes换一个名字。
import {PropTypes as observablePropTypes} from 'mobx-react'
queue: observablePropTypes.observableArray //queue: PropTypes.array
5)把对可观察数据的修改都封装到action中
在Store中声明action方法
class Store { @observable cache = {queue: []} @action.bound refresh() { this.cache.queue.push(1); } }
将refresh传入Foo组件
ReactDOM.render(<Foo cache={store.cache} refresh={store.refresh}/>,document.querySelector('#root'));
在Foo组件中声明button
render() { const cache = this.props.cache; return <div><button onClick={this.props.refresh}>Refresh</button><Bar queue={cache.queue} /></div>; }
但这时点击Refresh按钮并没有反应......
这是因为React组件并没有重新渲染,这时就需要mobx-react登场了!mobx-react可以将React组件的render方法包装成autorun,那我们执行action时是不是就可以触发组件重新渲染了呢?
首先从mobx-react中导入observer方法,该方法也是一个decorator修饰器,与普通修饰器不同的是,它不是用来修饰类成员的,而是用来修饰类本身的,修饰的类为React组件类。
import { observer } from 'mobx-react';
接下来尝试修饰一下Foo组件:
@observer class Foo extends Component { static propTypes = { cache: PropTypes.object }; render() { const cache = this.props.cache; return <div><button onClick={this.props.refresh}>Refresh</button><Bar queue={cache.queue} /></div>; } }
此时点击Refresh按钮仍然没有反应......
去掉对Foo的修饰,再尝试修饰一下Bar组件:
@observer class Bar extends Component { static propTypes = { queue: PropTypes.array // queue: observablePropTypes.observableArray }; render() { const queue = this.props.queue; return <span>{queue.length}</span>; } }
这时,按钮终于生效了!每点击一次数字就会增加1,React帮我们重新渲染组件了。
mobx能够精得知autorun依赖哪些可观察数据,做到按需触发,这两个组件虽然有上下级依赖关系,但Foo组件并没有使用到queue属性,而Bar组件用到了。
也就是说,谁真正用到了被修改到可观察数据,谁就会重新渲染,谁也就被observer修饰。
对没有使用任何可观察数据的组件,被修饰也没有什么副作用,因此,考虑到扩展性,建议修饰所有用到到组件。
React中的生命周期函数ShouldComponentUpdate()也可能会取消重新渲染,mobx-react也已经为React组件实现了一个ShouldComponentUpdate()方法,不再需要单独定义它,使得优化React应用程序更加的方便。
mobx-react只是mobx的一种应用场景,mobx并不局限于此。