日常使用mobx的小技巧

由于自己开发的项目都是中小型项目,所以在技术选型上使用了mobx。但是使用过程中发现关于mobx的技术文章并不多。于是萌发出写这篇文章的想法。请轻喷。

  • 更新控制store渲染的方法
mobx一些有关资料

中文文档

github仓库

npm地址

添加mobx
npm i mobx
npm i mobx-react

mobx用来操作store(也就是数据操作层,model层),而mobx-react则是用来操作view(也就是视图层,Component层)。

mobx常用操作符
  1. observable,将JS基本数据类型、引用类型、普通对象、类实例、数组和映射,转换为可观察数据。
  2. action,用来修改observable的数据的动作,只有actionrunInAction才能修改observable
  3. runInAction,用来在异步的时候执行修改observable的数据的动作。例如网络请求后修改数据。
  4. computed,根据现有的observable的值或其它计算值衍生出的值。只有在view使用了computed的值,computed才会执行计算
mobx-react常用操作符
  1. observer,将 React组件 转变成响应式组件。
  2. inject,将组件连接到提供的stores 。一般是用来连接到上层组件提供的store或者全局store
  3. Provider,它是一个react组件,用来向下传递 stores。任意子组件可以使用inject来获取Providerstore
代码

下面会贴点自己的代码。希望能给大家带来一些帮助。

全局store

// 文件 index.jsx
import { Provider } from "mobx-react";
import * as stores from "../../stores";
class MainView extends Component {
render() {
return (
<React.Fragment>
<Provider {...stores}> // 这里是全局stores的配置
<Switch>
{routers.map((item, index) => {
return (
<Route
exact
key={item.path}
path={item.path}
component={item.component}
/>
);
})}
</Switch>
</Provider>
</React.Fragment>
);
}
} // 文件 ../../stores/index.js
import aStore from "./aStore";
import bStore from "./bStore";
export { aStore, bStore}; // 文件 aStore.js
class AStore {
@observable info = {};
@observable line = {};
@action
onInfo = data => {
this.info = data;
};
@action
onLine = data => {
this.line = data;
};
}
const aStore = new AStore();
export default aStore; // 组件使用aStore
@inject(all => ({
aStore: all.aStore // 连接到aStore
}))
@observer
class Detail extends Component {
updateInfo = () => {
const aStore = this.props.aStore;
aStore.onInfo(info) // 改变store属性
}
render() {
const aStore = this.props.aStore; // 获取到全局store
return (
<div>
{aStore.info.name} // 使用里面的属性
<Button onClick={this.updateInfo}>改变info</Button>
</div>
);
}
}

组件内可观察数据。

@observer
class Detail extends Component {
@observable info = {};
@observable index = 1; @computed get sum() {
return index * 4
} @action
onInfo = data => {
this.info = data;
};
updateInfo = () => {
this.onInfo(info) // 改变store属性
}
render() {
return (
<div>
{this.info.name} // 使用里面的属性
<Button onClick={this.updateInfo}>改变info</Button>
</div>
);
}
}

最后一种是我自己项目使用的,个人觉得不错。可以分离逻辑层和视图层。如果想使用全局stores,直接用inject导入第一种方式注入的stores。能较好划分全局stores单业务store的职责,而不是无脑的以树的方式全挂在index.js上面。子组件最好跟父组件用同一个store,方便沟通的同时层级不多也不会导致store太过复杂。

// 逻辑层 用来处理业务逻辑
import { observable, runInAction } from "mobx";
import { aService, bService } from "../../../services/dispatch";
import { T } from "react-toast-mobile";
class ListStore {
@observable list = []; serInitData = async () => {
try {
T.loading();
const data = await aService()
runInAction("serInitData", () => {
this.list = data || [];
});
} catch (error) {
T.notify(error.message);
console.error(error);
} finally {
T.loaded();
}
}; serBService = async vehicleNum => {
try {
T.loading();
await bService(vehicleNum);
runInAction("serBService", () => {
this.list = this.list.filter(params => {
return params.vehicleNum != vehicleNum;
});
});
} catch (error) {
T.notify(error.message);
// eslint-disable-next-line no-console
console.error(error);
} finally {
T.loaded();
}
};
}
export default ListStore; // 视图层 纯粹的视图展示和操作触发
@observer
class Detail extends Component {
store = new ListStore(); componentDidMount() {
// 初始化数据
this.store.serInitData();
} updateInfo = () => {
this.store.serBService(); // 调用bService
}
render() {
return (
<div>
{this.store.list.map((item)=>{
return
<Provider myStore={this.store} >
<Item key={item.guid} />
</Provider>
})} // 轮询列表
<Button onClick={this.updateInfo}>改变info</Button>
</div>
);
}
} const Item = inject(allStores => ({
aStore: all.aStore, // 连接到aStore
myStore: allStores.myStore, // 连接到父组件的myStore
}))(
observer(function(props) { // 使用function方式在发送action等操作时,会带上Item这个组件名字,能变相的看到发送的来源。使用箭头函数则不会。而且react推荐的无状态组件也是使用的function return (
<div>
{this.props.aStore.xxxxx} // 使用全局store
{this.props.myStore.xxxxx} // 使用父组件的store
</div>
);
}));
一些备注
  1. 使用@inject后,无法通过组件的refs属性调用其对应的方法?
if (this.tabIndex == "0") {
// 加了@inject+@observer
this.biddingRef.current.wrappedInstance.openFilter();
} else if (this.tabIndex == "1") {
// 只有@observer
this.zdRef.current.openFilter();
}
参考链接
// https://stackoverflow.com/questions/43847401/reactnative-mobx-how-to-access-component-refs-from-mobx
  1. mobx如何自动保存数据
import { observable, action, autorun, toJS, set } from "mobx";

function autoSave(store, save) {
let firstRun = true;
autorun(() => {
// 此代码将在每次运行任何可观察属性时运行
// 对store进行更新。
const json = JSON.stringify(toJS(store));
if (!firstRun) {
save(json);
}
firstRun = false;
});
}
class RouteState {
@observable state = {};
constructor() {
this.load();
autoSave(this, this.save.bind(this));
}
load() {
const storeTemp = sessionStorage.getItem("route_state");
if (storeTemp) {
const data = JSON.parse(storeTemp);
set(this, data);
}
}
save(json) {
sessionStorage.setItem("route_state", json);
}
@action.bound
actionState(_state) {
this.state = _state;
}
} // 参考链接
https://stackoverflow.com/questions/40292677/how-to-save-mobx-state-in-sessionstorage
场景模拟

列表A中有一个倒计时,这个倒计时会改变dataListitem里面的时间戳.

列表所在的页面有个筛选浮层,筛选浮层中有DatePicker组件

遇到的问题

DatePicker选择其他时间1s后,时间会重置为初始设置的时间.

原因

列表A中的倒计时每秒都在改变dataList,这导致该页面的子组件每秒都会执行render函数.导致DatePicker中的时间重置为初始时间.

解决办法

github iss

// 新建一个包含组件.注意,这里不能用@observer将其包裹起来,
// 包含组件应该是个干净的,由你控制是否重新渲染的组件
class FilterPopContains extends Component {
shouldComponentUpdate(nextProps, nextState) {
// 在包含组件的shouldComponentUpdate方法中自己判断是否要执行render函数
if (JSON.stringify(nextProps) != JSON.stringify(this.props)) return true;
return false;
}
render() {
// 将props原封不动传递给逻辑组件
return <FilterPop {...this.props} />;
}
}
// 这个是具体的内容组件,里面有你的逻辑
@observer
class BiddingFilterPop extends Component {
render() {
return <div>
<DatePicker/>
</div>
}
}
  1. mobx的使用非常灵活。可以多种使用方式在同一个项目使用。并不冲突。
  2. 推荐所有的组件都observer化,这并不会造成性能损耗,反而会优化组件。
  3. 想不到了。想起来再更新吧。

日常使用mobx的小技巧的更多相关文章

  1. 前端ps实用小技巧

    下面总结了几个日常使用PS的小技巧,希望对大家有所帮助(重点推荐第一个小技巧) 场景一:用ps测量PSD图中的元素宽高间距时,一般是手动使用 测量,但其实是有快捷键的,如下图 首先选中元素相应图层,然 ...

  2. ( 译、持续更新 ) JavaScript 上分小技巧(四)

    后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...

  3. ( 译、持续更新 ) JavaScript 上分小技巧(一)

    感谢好友破狼提供的这篇好文章,也感谢写这些知识点的作者们和将他们整理到一起的作者.这是github上的一篇文章,在这里本兽也就只做翻译,由于本兽英语水平和编程能力都不咋地,如有不好的地方也请多理解体谅 ...

  4. asp.net mvc route 中新发现的小技巧

    在发现这个小技巧之前,我经常被某些问题困扰,我们以博客园为例 1:是分类名称 2:是分类url 3:点击分类,进入的页面,要显示分类的名称 4:点击分类,进入的页面,要用分类相关参数 在日常web的开 ...

  5. Fiddler-010-网络延时应用小技巧-模拟低网速环境

    在日常的网络测试中,经常需要测试网络超时或在网络传输速率不佳的情况的应用场景,而与此同时我们有时手边资源有限,实现在各种真实网络(2G\3G)环境下测试有些局限性.其实 fiddler 已经提供了类似 ...

  6. 8 个 Git 的小技巧

    git 已经成为了我日常必备工具之一,我总结我几乎每天使用的8个有用(且简洁)的git技巧.   使用-p选择性添加 当你想提交内容时,你可以通过使用 git commit -am 来选择所有文件或使 ...

  7. Vim实用小技巧

    Vim实用小技巧 一些网络上质量较高的Vim资料 从我07年接触Vim以来,已经过去了8个年头,期间看过很多的Vim文章,我自己觉得非常不错,而且创作时间也比较近的文章有如下这些. Vim入门 目前为 ...

  8. 11个不常被提及的JavaScript小技巧

    这次我们主要来分享11个在日常教程中不常被提及的JavaScript小技巧,他们往往在我们的日常工作中经常出现,但是我们又很容易忽略. 1.过滤唯一值 Set类型是在 ES6中新增的,它类似于数组,但 ...

  9. 分享几个 SpringBoot 实用的小技巧

    前言 最近分享的一些源码.框架设计的东西.我发现大家热情不是特别高,想想大多数应该还是正儿八经写代码的居多:这次就分享一点接地气的: SpringBoot 使用中的一些小技巧. 算不上多高大上的东西, ...

随机推荐

  1. 使用虚拟机在CentOS上安装部署数据库使用

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 本节描述使用数据库的基本操作.通过此节您可以完成创建数据库.创建表及向表中插入数据和查询表中数据等操作. 2.1 前提条件 ●openGauss正 ...

  2. 4月11日 python学习总结 对象与类

    1.类的定义 #类的定义 class 类名: 属性='xxx' def __init__(self): self.name='enon' self.age=18 def other_func: pas ...

  3. 面试官:Zookeeper是什么,它有什么特性与使用场景?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 作为一名Java程序员,Zook ...

  4. Spring Cloud Alibaba 之 Nacos

    Nacos 技术讲解 一提到分布式系统就不的不提一下 CAP 原则 什么是CAP CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency).可用性(Availability ...

  5. CF1487G String Counting (容斥计数)

    传送门 考虑$c[i]>n/3$这个关键条件!最多有2个字母数量超过$n/3$! 没有奇数回文?长度大于3的回文串中间一定是长度为3的回文串,所以合法串一定没有长度=3的回文,也就是$a[i]\ ...

  6. GitHub还能这样玩,这次我真是开了眼了

    哈喽,大家好,我是指北君. 我会一直在"开源指北"公众号给大家分享各种有趣. 实用与最前沿的开源项目,还有各种互联网干货, 今天主要给大家分享一下GitHub的一些使用技巧,帮助你 ...

  7. Android studio Error occurred during initialization of VM

    Unable to start the daemon process. This problem might be caused by incorrect configuration of the d ...

  8. java并发lock锁详解和使用

    一.synchronized的缺陷 synchronized是java中的一个关键字,也就是说是Java语言内置的特性.那么为什么会出现Lock呢? 在上面一篇文章中,我们了解到如果一个代码块被syn ...

  9. 数据库连接Database link?

    在一个用户下,可以获取到另外的用户下的表的数据,通常在跨数据库时使用. create database link link93 connect to scott identified by tiger ...

  10. Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法 ?

    面试官:想了解对 ES 集群的运维能力. 解答: 1.关闭缓存 swap; 2.堆内存设置为:Min(节点内存/2, 32GB); 3.设置最大文件句柄数: 4.线程池+队列大小根据业务需要做调整: ...