[Web 前端] mobx教程(三)-在React中使用Mobx
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的更多相关文章
- 推荐20个很有帮助的 Web 前端开发教程
在平常的搜索中,我碰到过很多有趣的信息,应用程序和文档,我把它们整理在下面这个列表.这是收藏的遇到的有用内容的一个伟大的方式,可以在你需要的时候方便查阅.相信你会在这个列表中发现对你很有用的资料. 您 ...
- Web前端入门教程之浏览器兼容问题及解决方法
JavaScript 被称为JS,是作为浏览器的内置脚本语言,为我们提供操控浏览器的能力,可以让网页呈现出各种特殊效果,为用户提供友好的互动体验.JS是Web前端入门教程中的重点和难点,而浏览器兼容性 ...
- 推荐20个很有帮助的web前端开发教程
1. CSS Vocabulary 一个伟大的指向和点击的小应用程序,让你加快速度掌握 CSS 语法的各个不同部分,学习各个属性的正确的名称. 2. Liquidapsive 一个简单的信息化布局,通 ...
- 推荐20个非常有帮助的web前端开发教程
1. CSS Vocabulary 一个伟大的指向和点击的小应用程序,让你加高速度掌握 CSS 语法的各个不同部分,学习各个属性的正确的名称. 2. Liquidapsive 一个简单的信息化布局.通 ...
- web前端该怎么入门?web前端入门教程(非常详细)
初学编程的小伙伴经常会遇到的问题,1.没资源 2.没人带 3.不知道从何开始 ,小编也是从新手期过来的,所以很能理解萌新的难处,现在整理一些以前自己学习的一些资料送给大家,希望对广大初学小伙伴有帮助! ...
- web前端开发教程系列-2 - 前端开发书籍分享(转)
目录: 前言 一. CSS 二. JavaScript 三. jQuery 四. 后记 前言 前端书籍在每个商城或书架上面都是琳琅满目,很多初学者又不能很好的判断书的质量或层次.因为今天给同学们分 ...
- web前端开发教程系列-2 - 前端开发书籍分享
目录: 前言 一. CSS 二. JavaScript 三. jQuery 四. 后记 前言 前端书籍在每个商城或书架上面都是琳琅满目,很多初学者又不能很好的判断书的质量或层次.因为今天给同学们分 ...
- web前端开发教程系列-4 - 前端开发职业规划
前言 关于我:小天 1). 架构师,项目经理,产品经理 2). 中间件研发 3). VPCC 云计算基础平台管理 4). 智慧旅游 5). 智慧教育 6). 一次失败的创业体验(爱邂逅网) 一. 在开 ...
- web前端学习(三)css学习笔记部分(8)-- SVN的介绍和应用、CSS动画效果、CSS3布局属性全接触
15.SVN的介绍和应用 15.1.SVN的介绍和应用课程概要 将代码进行集中管理,有版本号的进行迭代,方便集体工作的build流程 15.2.SVN的介绍 SVN是Subversion的简称,是一个 ...
随机推荐
- jenkins(4): jenkins 插件
1. jenkins插件下载镜像加速 jenkins插件清华大学镜像地址 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-ce ...
- jquery|js|jq常用正则
var mobReg=/^1[34578]\d{9}$/; //手机号 if (!mobReg.test(mob)) { mui.alert("请填写正确手机号!"," ...
- BZOJ3262/洛谷P3810 陌上花开 分治 三维偏序 树状数组
原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 洛谷P3810 题意 有$n$个元素,第 ...
- Date、Calendar、DateFormat类
Date类与Calendar类之间的转换 package date; import java.util.Calendar; import java.util.Date; public class Da ...
- 1402 后缀数组 (hash+二分)
描述 后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围.在本题中,我们希望使用快排.Hash与二分实现一个简单的 O(n log^2n ) 的后缀数组 ...
- POJ 1988 Cube Stacking 【带权并查集】
<题目链接> 题目大意: 有几个stack,初始里面有一个cube.支持两种操作: 1.move x y: 将x所在的stack移动到y所在stack的顶部. 2.count x:数在x所 ...
- java设计模式之-观察者模式(发布-订阅模式)
1.观察者模式定义 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象. 这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己. 2.观察者模式结构 ...
- DRF的视图
DRF的视图 APIView 我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不同呢~~~ urlpatterns = [ ...
- JS获取IOS版本号
var str= navigator.userAgent.toLowerCase(); var ver=str.match(/cpu iphone os (.*?) like mac os/); if ...
- ubuntu16 64 搭建lnmp环境
//安全设置linux(ubuntu16 64) 安全设置1.修改ssh端口 vi /etc/ssh/sshd_config 如果用户想让22和60000端口同时开放,只需在/etc/ssh/sshd ...