日常使用mobx的小技巧
日常使用mobx的小技巧
由于自己开发的项目都是中小型项目,所以在技术选型上使用了mobx。但是使用过程中发现关于mobx的技术文章并不多。于是萌发出写这篇文章的想法。请轻喷。
- 更新控制store渲染的方法
mobx一些有关资料
添加mobx
npm i mobx
npm i mobx-react
mobx用来操作store(也就是数据操作层,model层),而mobx-react则是用来操作view(也就是视图层,Component层)。
mobx常用操作符
- observable,将
JS
基本数据类型、引用类型、普通对象、类实例、数组和映射,转换为可观察数据。 - action,用来修改
observable
的数据的动作,只有action
和runInAction
才能修改observable
。 - runInAction,用来在异步的时候执行修改
observable
的数据的动作。例如网络请求后修改数据。 - computed,根据现有的
observable
的值或其它计算值衍生出的值。只有在view
使用了computed
的值,computed
才会执行计算
mobx-react常用操作符
- observer,将
React组件
转变成响应式组件。 - inject,将组件连接到提供的
stores
。一般是用来连接到上层组件提供的store
或者全局store
。 - Provider,它是一个
react组件
,用来向下传递stores
。任意子组件可以使用inject
来获取Provider
的store
。
代码
下面会贴点自己的代码。希望能给大家带来一些帮助。
全局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>
);
}));
一些备注
- 使用
@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
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中有一个倒计时,这个倒计时会改变dataList
中item
里面的时间戳.
列表所在的页面有个筛选浮层,筛选浮层中有DatePicker
组件
遇到的问题
DatePicker
选择其他时间1s后,时间会重置为初始设置的时间.
原因
列表A中的倒计时每秒都在改变dataList
,这导致该页面的子组件每秒都会执行render
函数.导致DatePicker
中的时间重置为初始时间.
解决办法
// 新建一个包含组件.注意,这里不能用@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>
}
}
mobx
的使用非常灵活。可以多种使用方式在同一个项目使用。并不冲突。- 推荐所有的组件都
observer
化,这并不会造成性能损耗,反而会优化组件。 - 想不到了。想起来再更新吧。
日常使用mobx的小技巧的更多相关文章
- 前端ps实用小技巧
下面总结了几个日常使用PS的小技巧,希望对大家有所帮助(重点推荐第一个小技巧) 场景一:用ps测量PSD图中的元素宽高间距时,一般是手动使用 测量,但其实是有快捷键的,如下图 首先选中元素相应图层,然 ...
- ( 译、持续更新 ) JavaScript 上分小技巧(四)
后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...
- ( 译、持续更新 ) JavaScript 上分小技巧(一)
感谢好友破狼提供的这篇好文章,也感谢写这些知识点的作者们和将他们整理到一起的作者.这是github上的一篇文章,在这里本兽也就只做翻译,由于本兽英语水平和编程能力都不咋地,如有不好的地方也请多理解体谅 ...
- asp.net mvc route 中新发现的小技巧
在发现这个小技巧之前,我经常被某些问题困扰,我们以博客园为例 1:是分类名称 2:是分类url 3:点击分类,进入的页面,要显示分类的名称 4:点击分类,进入的页面,要用分类相关参数 在日常web的开 ...
- Fiddler-010-网络延时应用小技巧-模拟低网速环境
在日常的网络测试中,经常需要测试网络超时或在网络传输速率不佳的情况的应用场景,而与此同时我们有时手边资源有限,实现在各种真实网络(2G\3G)环境下测试有些局限性.其实 fiddler 已经提供了类似 ...
- 8 个 Git 的小技巧
git 已经成为了我日常必备工具之一,我总结我几乎每天使用的8个有用(且简洁)的git技巧. 使用-p选择性添加 当你想提交内容时,你可以通过使用 git commit -am 来选择所有文件或使 ...
- Vim实用小技巧
Vim实用小技巧 一些网络上质量较高的Vim资料 从我07年接触Vim以来,已经过去了8个年头,期间看过很多的Vim文章,我自己觉得非常不错,而且创作时间也比较近的文章有如下这些. Vim入门 目前为 ...
- 11个不常被提及的JavaScript小技巧
这次我们主要来分享11个在日常教程中不常被提及的JavaScript小技巧,他们往往在我们的日常工作中经常出现,但是我们又很容易忽略. 1.过滤唯一值 Set类型是在 ES6中新增的,它类似于数组,但 ...
- 分享几个 SpringBoot 实用的小技巧
前言 最近分享的一些源码.框架设计的东西.我发现大家热情不是特别高,想想大多数应该还是正儿八经写代码的居多:这次就分享一点接地气的: SpringBoot 使用中的一些小技巧. 算不上多高大上的东西, ...
随机推荐
- python3求200以内能被17整除的最大正整数
for i in range(200, 17,-1): if(i%17==0): print(i) break
- nginx配置限制同一个ip的访问频率方法
1.在nginx.conf里的http{}里加上如下代码: limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn_zone ...
- springcloud学习04- 断路器Spring Cloud Netflix Hystrix
依赖上个博客:https://www.cnblogs.com/wang-liang-blogs/p/12072423.html 1.断路器存在的原因 引用博客 https://blog.csdn.ne ...
- vivo 商品中台的可视化微前端实践
一.背景 在电商领域内,商品是一个重要组成部分,与其对应的商品管理系统,则负责商品的新建.编辑.复制等功能.随着商品管理系统的成熟稳定和业务上的扩展需求,催化出了商品中台的诞生.它可以将现有商品功能最 ...
- Gradle Gretty进行runAppDebug的Listening for transport dt_socket at address: 5005 的后续配置
出现 Listening for transport dt_socket at address: 5005:代表debug端口已启动好了,接下来你需要进行配置远程Debug,进行附加Debug进程: ...
- SpringBoot bean映射yml中的属性举例
pom:导入配置文件处理器,配置文件进行绑定就会有提示 <dependency> <groupId>org.springframework.boot</groupId&g ...
- Mybatis的XML文件调用静态方法
如果需要在Mapper文件中调用静态方法,需要 <choose> // 需要静态方法返回true还是false <when test="@staticClass@stati ...
- SpringBoot项目意外出现 循环依赖和注入的对象意外是Null的问题 Requested bean is currently in creation: Is there an unresolvable circular reference? 或 nested exception is java.lang.NullPointerException
1.Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ...
- hdu 1175 连连看 DFS_字节跳动笔试原题
转载至:https://www.cnblogs.com/LQBZ/p/4253962.html Problem Description "连连看"相信很多人都玩过.没玩过也没关系, ...
- MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象
我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ...