copy from : https://blog.csdn.net/smk108/article/details/85053903

Mobx提供了一个mobx-react包帮助开发者方便地在React中使用Mobx,mobx-react中有observer、Provider、inject几个常用的api。在《mobx系列(二)-mobx主要概念》中我们已经介绍过observer,本文介绍下inject、Provider,以及Mobx如何与React结合使用。

1、Provider

Provider是一个React组件,使用React的上下文(context)机制,可以用来向下传递stores,即把state传递给其子组件。

例如,有如下形式的一个store:

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,可以使用类似于如下形式:

const stores = {
mainStore, userStore, commonStore
};
ReactDOM.render((
<Provider {...stores}>
<App />
</Provider>
), document.getElementById('container'));

2、@inject

inject是一个高阶组件,作用是将组件连接到提供的stores。具体说是与Provider结合使用,从Provider提供给应用的state数据中选取所需数据,以props的形式传递给目标组件。用法为:

inject(stores)(component)
@inject(stores) class Component...

对应上节的例子,App内使用的组件User使用@inject方式为:

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>
);
}
}

3、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中使用的数据结构间的不同。

4、可观察的局部组件状态

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;
5、生命周期钩子

当使用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也会触发此钩子;
6、React优化

本小节介绍几项基本的React优化策略,有些是基于在React中使用Mobx时特有的策略,有些是会用React通用的策略。

使用大量的小组件
@observer 组件会追踪它们使用的所有值,并且当它们中的任何一个改变时重新渲染。 所以你的组件越小,它们需要重新渲染产生的变化则越小;这意味着用户界面的更多部分具备彼此独立渲染的可能性。

在专用组件中渲染列表(避免多个组件受影响,一起重新渲染)
不要使用数组的索引作为 key(虚拟dom)
不用使用数组索引或者任何将来可能会改变的值作为 key

晚一点使用间接引用值
使用 mobx-react 时,推荐尽可能晚的使用间接引用值。 这是因为当使用 observable 间接引用值时 MobX 会自动重新渲染组件。 如果间接引用值发生在组件树的层级越深,那么需要重新渲染的组件就越少。

[Web 前端] mobx教程(三)-在React中使用Mobx的更多相关文章

  1. 推荐20个很有帮助的 Web 前端开发教程

    在平常的搜索中,我碰到过很多有趣的信息,应用程序和文档,我把它们整理在下面这个列表.这是收藏的遇到的有用内容的一个伟大的方式,可以在你需要的时候方便查阅.相信你会在这个列表中发现对你很有用的资料. 您 ...

  2. Web前端入门教程之浏览器兼容问题及解决方法

    JavaScript 被称为JS,是作为浏览器的内置脚本语言,为我们提供操控浏览器的能力,可以让网页呈现出各种特殊效果,为用户提供友好的互动体验.JS是Web前端入门教程中的重点和难点,而浏览器兼容性 ...

  3. 推荐20个很有帮助的web前端开发教程

    1. CSS Vocabulary 一个伟大的指向和点击的小应用程序,让你加快速度掌握 CSS 语法的各个不同部分,学习各个属性的正确的名称. 2. Liquidapsive 一个简单的信息化布局,通 ...

  4. 推荐20个非常有帮助的web前端开发教程

    1. CSS Vocabulary 一个伟大的指向和点击的小应用程序,让你加高速度掌握 CSS 语法的各个不同部分,学习各个属性的正确的名称. 2. Liquidapsive 一个简单的信息化布局.通 ...

  5. web前端该怎么入门?web前端入门教程(非常详细)

    初学编程的小伙伴经常会遇到的问题,1.没资源 2.没人带 3.不知道从何开始 ,小编也是从新手期过来的,所以很能理解萌新的难处,现在整理一些以前自己学习的一些资料送给大家,希望对广大初学小伙伴有帮助! ...

  6. web前端开发教程系列-2 - 前端开发书籍分享(转)

    目录: 前言 一. CSS 二. JavaScript 三. jQuery 四. 后记   前言 前端书籍在每个商城或书架上面都是琳琅满目,很多初学者又不能很好的判断书的质量或层次.因为今天给同学们分 ...

  7. web前端开发教程系列-2 - 前端开发书籍分享

    目录: 前言 一. CSS 二. JavaScript 三. jQuery 四. 后记   前言 前端书籍在每个商城或书架上面都是琳琅满目,很多初学者又不能很好的判断书的质量或层次.因为今天给同学们分 ...

  8. web前端开发教程系列-4 - 前端开发职业规划

    前言 关于我:小天 1). 架构师,项目经理,产品经理 2). 中间件研发 3). VPCC 云计算基础平台管理 4). 智慧旅游 5). 智慧教育 6). 一次失败的创业体验(爱邂逅网) 一. 在开 ...

  9. web前端学习(三)css学习笔记部分(8)-- SVN的介绍和应用、CSS动画效果、CSS3布局属性全接触

    15.SVN的介绍和应用 15.1.SVN的介绍和应用课程概要 将代码进行集中管理,有版本号的进行迭代,方便集体工作的build流程 15.2.SVN的介绍 SVN是Subversion的简称,是一个 ...

随机推荐

  1. Codeforces 513E2 Subarray Cuts dp (看题解)

    我们肯定要一大一小间隔开来所以 把式子拆出来就是类似这样的形式 s1 - 2 * s2 + 2 * s3 + ...... + sn 然后把状态开成四个, 分别表示在顶部, 在底部, 在顶部到底部的中 ...

  2. JavaSE| 面向对象-类的五大成员

    面向对象 面向对象只是其中一种编程思想,还有很多其他的编程思想:面向过程.面向切面.面向服务编程... 面向过程的思维方式:注重步骤.过程,面向过程强调的是功能行为: 面向对象的思维方式:关注的是“对 ...

  3. rest模式get,post,put,delete简单讲解

    1.请求方法为get时,会向数据库请求数据,类似于select语言,只能达到查询的效果,不会添加,修改,不会影响资源的内容,无副作用 2.请求方法为post时,该方法,用于向服务器添加数据,可以改变数 ...

  4. PHP环境配置错误处理

    [Linux apt-get 更换源] 1.问题描述:按照网上的教程编辑源列表文件后发现apt-get update 出现各种错误,导致更新失败 sudo vim /etc/apt/sources.l ...

  5. Nowcoder contest 370H Rinne Loves Dynamic Graph【分层图最短路】

    <题目链接> 题目大意:Rinne 学到了一个新的奇妙的东西叫做动态图,这里的动态图的定义是边权可以随着操作而变动的图.当我们在这个图上经过一条边的时候,这个图上所有边的边权都会发生变动. ...

  6. javaScript函数节流与函数防抖

    javaScript函数节流与防抖之区别 函数防抖(debounce)与函数节流(throttle)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟.假死或卡顿 ...

  7. 从小白到区块链工程师:第一阶段:Go语言环境的搭建(1)

    一,Golang语言简介 2009年由谷歌公司推出,由C语言之父Ken Thompson主导研发.Go(又称Golang)是Google开发的一种静态强类型.编译型.并发型,并具有垃圾回收功能的编程语 ...

  8. 转载:ThreadPoolExecutor 源码阅读

    前言 之前研究了一下如何使用ScheduledThreadPoolExecutor动态创建定时任务(Springboot定时任务原理及如何动态创建定时任务),简单了解了ScheduledThreadP ...

  9. MySQL安装目录修改

  10. 表单提交和ajax提交数据的请求区别

    在http请求中,我们通常会看到请求字段以query string parameters,或form data,或request payload形式发送到服务器,究竟他们有什么区别呢?下面为您揭晓答案 ...