copy from : https://blog.csdn.net/smk108/article/details/85053903css
Mobx提供了一个mobx-react包帮助开发者方便地在React中使用Mobx,mobx-react中有observer、Provider、inject几个经常使用的api。在《mobx系列(二)-mobx主要概念》中咱们已经介绍过observer,本文介绍下inject、Provider,以及Mobx如何与React结合使用。react
一、Providergit
Provider是一个React组件,使用React的上下文(context)机制,能够用来向下传递stores,即把state传递给其子组件。github
例如,有以下形式的一个store:api
import {observable, computed, action} from 'mobx'; class userStoreClass { @observable user = { name: 'admin', role: '管理员' }; count = 0; @computed get userName(){ return this.user.name; } @action changeUser(){ if(this.count % 2 === 1){ this.user = { name: 'admin', role: '管理员' }; }else{ this.user.name = 'guest'; this.user.role = '访客'; this.user.isGuest = 'true'; } this.count ++; } } const userStore = new userStoreClass(); export default userStore;
使用Provider传递store的方式为:数组
import React from 'react'; import ReactDOM from 'react-dom'; import {configure} from 'mobx'; import {Provider} from 'mobx-react'; import userStore from './models/userStore'; import App from './components/App'; // 状态始终须要经过动做来更新(实际上还包括建立) configure({'enforceActions': 'always'}); ReactDOM.render(( <Provider store={userStore}}> <App /> </Provider> ), document.getElementById('container'));
若是有多个store,可使用相似于以下形式:antd
const stores = {
mainStore, userStore, commonStore
};
ReactDOM.render((
<Provider {...stores}>
<App />
</Provider>
), document.getElementById('container'));
二、@inject数据结构
inject是一个高阶组件,做用是将组件链接到提供的stores。具体说是与Provider结合使用,从Provider提供给应用的state数据中选取所需数据,以props的形式传递给目标组件。用法为:dom
inject(stores)(component)
@inject(stores) class Component...
对应上节的例子,App内使用的组件User使用@inject方式为:ide
import React, {Component} from 'react'; import {inject, observer} from 'mobx-react'; import {Button} from 'antd'; import './style.css'; @inject( 'userStore') @observer export default class User extends Component{ constructor(props){ super(props); this.state = {}; } render(){ // 能够以this.props.userStore形式获取store内state const {user} = this.props.userStore; // 以.形式使用对象的属性值 return( <div className='user'> <div className='user_list'>name:{user.name}</div> <div className='user_list'>role:{user.name}</div> <div className='user_list'>{user.isGuest ? `isGuest:${user.isGuest}` : ''}</div> <Button type='primary' onClick={() => this.props.userStore.changeUser()}>Change User</Button> </div> ); } }
三、react-mobx实践示例
我写了一个react-mobx的简单demo,地址为:https://github.com/smk108/mobx_demo ,
demo的结构为:
依据组件的划分使用了3个store,须要说明的是我是以class的形式建立的store,store中export的是store class的instance,例如第一节中userStore的形式:
const userStore = new userStoreClass(); export default userStore;
在React中使用Mobx的方式有不少,Mobx不会强制要求以某种方式使用它,我在demo中使用的方式仅仅是其中一种。事实上,你能够以任何你喜欢而且能生效的方式使用它。在下一篇《Mobx定义数据存储》中会介绍、对比文档推荐使用的数据存储和个人demo中使用的数据结构间的不一样。
四、可观察的局部组件状态
Mobx容许在响应式React组件内使用自由地使用状态,意味着咱们能够将一些状态像普通React组件同样管理,例如对上面提到的demo中User组件作以下修改:
import React, {Component} from 'react'; import {inject, observer} from 'mobx-react'; import {Button} from 'antd'; import Timer from '../Timer'; import './style.css'; @inject( 'userStore') @observer export default class User extends Component{ constructor(props){ super(props); this.state = { userChangeTimes: 0 }; } handleChangeUser(){ this.props.userStore.changeUser(); let {userChangeTimes} = this.state; userChangeTimes ++ ; this.setState({userChangeTimes}); } render(){ const {user} = this.props.userStore; return( <div className='user'> <div className='user_list'>name:{user.name}</div> <div className='user_list'>role:{user.name}</div> <div className='user_list'>{user.isGuest ? `isGuest:${user.isGuest}` : ''}</div> <div>user change times: {this.state.userChangeTimes}</div> <Button type='primary' onClick={this.handleChangeUser.bind(this)}>Change User</Button> <Timer /> </div> ); } }
User组件state的userChangeTimes可使用setState进行修改,一切都和不使用Mobx时同样。可是,推荐响应式组件应该没有或不多有状态,由于在与其余组件共享的对象中封装(视图)状态一般更方便。针对响应式组件须要维护单独状态的状况,Mobx为咱们提供了更加方便的一种方式-可观察的局部组件状态。
Mobx容许使用@observable在React组件内引入可观察属性,意味着咱们不须要经过React 的冗长和强制性的 setState 机制也能够在组件中拥有功能一样强大的本地状态(local state)。
用法以下(使用demo中Timer组件举例):
import React, {Component} from 'react'; import {inject, observer} from 'mobx-react'; import {observable, action} from "mobx"; import './style.css'; @inject('commonStore') @observer export default class Timer extends Component{ constructor(props){ super(props); this.state = {}; } @observable secondsPassed = 0; componentWillMount(){ this.props.commonStore.startTime(); this.timer = setInterval(this.handleChangeSecondsPassed,1000); } @action.bound handleChangeSecondsPassed(){ this.secondsPassed ++; } render(){ const {time} = this.props.commonStore; return( <div className='time_content'> <div>{time}</div> <div>Seconds passed:{this.secondsPassed}</div> </div> ); } }
secondsPassed做为组件内可观察的局部状态,不使用setState也触发UI的响应。
须要注意的是:
可观察局部状态会被render提取调用;
可观察局部状态的修改会触发React的componentWillUpdate和componentDidUpdate生命周期,不会触发其它的生命周期;
若是你须要使用React的其它生命周期方法,请使用基于state的常规React API;
五、生命周期钩子
当使用mobx-react时能够定义一个新的生命周期钩子函数componentWillReact,当组件由于它观察的状态发生改变时,组件会从新渲染,这时componentWillReact会触发,能够帮助追溯渲染并找到致使渲染的动做(action)。
修改demo中User组件举例以下:
import React, {Component} from 'react'; import {inject, observer} from 'mobx-react'; import {Button} from 'antd'; import Timer from '../Timer'; import './style.css'; @inject( 'userStore') @observer export default class User extends Component{ constructor(props){ super(props); this.state = { userChangeTimes: 0 }; } handleChangeUser(){ this.props.userStore.changeUser(); let {userChangeTimes} = this.state; userChangeTimes ++ ; this.setState({userChangeTimes}); } componentWillReact() { console.log("I will re-render, since the user has changed!"); } render(){ const {user} = this.props.userStore; return( <div className='user'> <div className='user_list'>name:{user.name}</div> <div className='user_list'>role:{user.name}</div> <div className='user_list'>{user.isGuest ? `isGuest:${user.isGuest}` : ''}</div> <div>user change times: {this.state.userChangeTimes}</div> <Button type='primary' onClick={this.handleChangeUser.bind(this)}>Change User</Button> <Timer /> </div> ); } }
须要注意的是:
componentWillReact 不接收参数;
componentWillReact 初始化渲染前不会触发 (使用 componentWillMount 替代);
componentWillReact 对于 mobx-react@4+, 当接收新的 props 时并在 setState 调用后会触发此钩子;
像User组件内经过setState修改userChangeTimes也会触发此钩子;
六、React优化
本小节介绍几项基本的React优化策略,有些是基于在React中使用Mobx时特有的策略,有些是会用React通用的策略。
使用大量的小组件
@observer 组件会追踪它们使用的全部值,而且当它们中的任何一个改变时从新渲染。 因此你的组件越小,它们须要从新渲染产生的变化则越小;这意味着用户界面的更多部分具有彼此独立渲染的可能性。
在专用组件中渲染列表(避免多个组件受影响,一块儿从新渲染)
不要使用数组的索引做为 key(虚拟dom)
不用使用数组索引或者任何未来可能会改变的值做为 key
晚一点使用间接引用值使用 mobx-react 时,推荐尽量晚的使用间接引用值。 这是由于当使用 observable 间接引用值时 MobX 会自动从新渲染组件。 若是间接引用值发生在组件树的层级越深,那么须要从新渲染的组件就越少。