惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
博客园_首页
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
宝玉的分享
宝玉的分享
博客园 - 叶小钗
Jina AI
Jina AI
罗磊的独立博客
Simon Willison's Weblog
Simon Willison's Weblog
Scott Helme
Scott Helme
D
DataBreaches.Net
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
Know Your Adversary
Know Your Adversary
博客园 - Franky
AWS News Blog
AWS News Blog
S
Schneier on Security
K
Kaspersky official blog
I
Intezer
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
L
LINUX DO - 热门话题
GbyAI
GbyAI
月光博客
月光博客
C
Cisco Blogs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
GRAHAM CLULEY
P
Privacy International News Feed
P
Privacy & Cybersecurity Law Blog
Hugging Face - Blog
Hugging Face - Blog
P
Proofpoint News Feed
T
Tor Project blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
T
Threat Research - Cisco Blogs
IT之家
IT之家
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Help Net Security
S
Security Affairs
V
Visual Studio Blog
C
CERT Recently Published Vulnerability Notes
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
S
SegmentFault 最新的问题
MongoDB | Blog
MongoDB | Blog
T
Troy Hunt's Blog

一颗小树

周更的第 100 篇 改变阅读方式 宝贵的人生建议 小树的工具库 2023 读《重构》有感 仅需 10 分钟,用 GPTs 实现文章总结助手 高质量的需求交付 产品始于问题,而不是解决方案 如何更好地休息 最优解人生 与体重斗,其乐无穷 结构化 prompt = 数字员工? 持续创作的法门 如何降低知识焦虑 7 月思维碎片 N 倍生产力提升:我的 AI 助理 Indie Hacker,互联网打工人的下一个出路? 如何成就伟大事业 夏日碎片 小报编辑的自我修养 一颗小树 #49 投入真实生活 一颗小树 #48 过年杂记 一颗小树 #47 我的人生信念(2023) 一颗小树 #46 回本就卖 一颗小树 #45 规划和落地 小树的 2022 年终总结 一颗小树 #44 构建高质量信源 一颗小树 #43 我的 2022 书单 一颗小树 #42 阳了怎么办 一颗小树 #41 一人企业 一颗小树 #40 非必要别正常啦 一颗小树 #39 阅读和创造 一颗小树 #38 疫情生活碎片 一颗小树 #37 基于多维表格的可转债投资系统 一颗小树 #36 飞盘初体验 一颗小树 #35 雁栖湖半日游 一颗小树 #34 初探多维表格 一颗小树 #33 回不去的名字叫家乡 一颗小树 #32 生活需要留白 一颗小树 #31 Figma 的成功之道 一颗小树 #30 拓宽自己 拥抱善意 一颗小树 #29 有关下雨的记忆 一颗小树 #28 隐入尘烟 一颗小树 #27 找到并坚持自己的热爱 一颗小树 #26 好产品的“差”改版 一颗小树 #25 吹吹南澳岛的海风 一颗小树 #24 代码重构的一点心得 一颗小树 #23 和团队新同学的对话 一颗小树 #22 从《干法》中学到的 一颗小树 #21 阿里四年我的收获和感想 一颗小树 #20 周更半年我学到的事 一颗小树 #19 慢慢来比较快 一颗小树 #18 只规划每天最重要的三件事 一颗小树 #17 裁员潮下的反思 一颗小树 #16 纪录片的力量在于真实 一颗小树 #15 世界很小但很好 一颗小树 #14 让自己成为问题的终结者 一颗小树 #13 别忘记你的热爱 一颗小树 #12 聊聊写作这件事 一颗小树 #11 开始投资前更重要的事 一颗小树 #10 疫情囤货指南 一颗小树 #9 疫情之下 重建内心的秩序 一颗小树 #8 不要倒在黎明前 一颗小树 #7 从小孩子身上学到的事 一颗小树 #6 和自己的产品一起成长 一颗小树 #5 技术对生产力的的变革是不可阻挡的 一颗小树 #4 暴风雨的意义 一颗小树 #3 投资成功,是我们变成一个更好的人之后自然的结果 一颗小树 #2 持续学习来应对这个复杂多变的世界 一颗小树 #1 任天堂和上岭村 一颗小树 #0 这是写给你们的第一封信 游戏改变世界 把自己给开源了 构建自己的不为清单 有爱和被爱 做了一点微小的工作 小树的 2021 年终总结 小树的 2020 年终总结 与其感慨路难行,不如马上出发 阿里前端也切图?不,人工智能帮你做 如何写好简历,拿到大厂 offer 的敲门砖 任时光匆匆流去 | 2019 年终总结 聊聊在阿里远程办公那点事儿 在 D2 做主持人是怎样一种体验? 提高工作效率的几个方法 有限状态机在 CSS 动画中的应用 「译」React 项目结构和组件命名之道 编写小而美函数的艺术 使用纯粹的JS构建 Web Component 翻译计划-状态管理请三思 利用Dawn工程化工具实践MobX数据流管理方案 高性能 MobX 模式(part 3)- 用例教程 技术文章写法浅谈 翻译计划-用node.js开发一个可交互的命令行应用 无他,唯手熟尔-前端实习面试题篇 工欲善其事必先利其器-前端实习简历篇 手把手带你用原生js实现css属性的set和get 我们来翻翻元素样式的族谱-getComputedStyle 翻译计划-从sass到PostCSS 把简单做好也不简单-css水平垂直居中
高性能 MobX 模式(part 2)- 响应变化
也树 · 2017-07-24 · via 一颗小树

在 Part 1 我们看到如何去建立一个 MobX 状态树并且让它可观察。在这个基础上,我们下一步要做的是开始响应数据的变化。坦白说,有趣的部分是从这里开始的。

译者:阿里云前端-也树

原文链接:

MobX 可以保证,无论何时你的响应式数据发生了变化,相应的依赖于 observable 的属性会自动同步更新。这意味着你现在可以专注于响应变化和处理变化带来的副作用,而不需要为数据的同步操心。

让我们深入一下,看看有哪些方式可以让你处理副作用。

使用 @action 作为入口

默认情况下,当你修改被监听的变量值,MobX 能够发觉并且保持其它依赖这个变量的值同步更新。这个过程是同步发生的。然而在很多情况下,你会想要在一个方法里修改多个被监听的变量值。这会导致许多通知被触发并且有可能会使你的应用运行变慢。

将你要触发的方法放在一个 action() 中是一个更好的做法。这会在你的方法上创建一个数据处理的边界,所有受影响被观察的变量会在你的 action 执行后保持同步更新。注意这个延迟后的通知只会对当前函数作用域下被观察的变量生效。如果你有许多会更改被观察变量的异步 action,就需要把他们放在 runInAction() 方法里了。

class Person {
  @observable firstName;
  @observable lastName;

  // 因为我们用 @action 装饰器来装饰这个方法,fullName 只会在 changeName() 执行完成后改变。
  @action
  changeName(first, last) {
    this.firstName = first;
    this.lastName = last;
  }

  @computed get fullName() {
    return `${this.firstName}, ${this.lastName}`;
  }
}

const p = new Person();
p.changeName("Pavan", "Podila");

action 是 store 产生变化的入口。通过使用 action 方法,你可以让更新多个被观察的变量变成原子性的操作。

tip: 尽可能避免直接从外界操作被观察的变量,同时显式的为你做数据变化的方法添加 @action 装饰器。事实上,你可以通过设置 useStrict(true) 来强制禁止在外界操作。

使用 autorun 来触发副作用

MobX 可以保证被观察变量的结构是稳定不变的。但是如果 MobX 的世界里只有被观察到的变量,是不是太无趣了一点。我们需要它们的一个对应产物 observers 来让事情有趣一点。

事实上,UI 就是 MobX store 美化后的一名观察者。通过使用 mobx-react 可以让你的 React 组件观察对应 store 的变动并且无论何时 store 发生了变化,这些组件会自动重新渲染。

但是,UI 不是你系统中唯一的观察者。你可以在你的 store 上添加更多的观察者,让它们去做一些有趣的事情。console-logger 可以作为一名最基础的观察者,它的功能就是在观察的变量有变更时,把变更后的值打印出来。

通过 autorun 方法我们可以非常容易的创建一名观察者。最快的方式就是给 autorun 方法提供一个函数。无论你在这个函数里用到了哪些被观察的变量,它们都会自动地被 MobX 追踪。一旦这些变量发生变化,你提供的函数会再次执行,也就是 autorun 的功能。

class Person {
  @observable firstName = "None";
  @observable lastName = "None";

  constructor() {
    // 一个简单的控制台日志功能
    autorun(() => {
      console.log(`Name changed: ${this.firstName}, ${this.lastName}`);
    });

    // 这里也会触发一次 autorun
    this.firstName = "Mob";

    // 这里又触发了一次 autorun
    this.lastName = "X";
  }
}

// 控制台输出: Name changed: None, None
// 控制台输出: Name changed: Mob, None
// 控制台输出: Name changed: Mob, X

上面的日志你也看到了,autorun方法会立即触发,并且每一次的触发都会有追踪的变量发生变化。但如果你仅仅想要在被观察的变量有变化的时候触发,而不想立即去执行 autorun,这个时候要怎么办呢?继续往下读,我们有 reaction 方法来解决这个问题。

使用 reaction 方法,在初次数据变化后触发副作用

reaction 相较于 autorun 提供了更符合直觉的控制方式。首先,它不会立即执行,而是会等到追踪的被观察变量第一次发生变化后才会执行。它的 API 相较于 autorun 也有微小的区别,最简单的情况你要提供两个参数:

reaction(
  () => data,
  data => {
    /* side effect */
  }
);

第一个函数(追踪函数)需要返回用来追踪的数据 data。data 会被传入第二个函数(效果函数)。效果函数是不会被追踪的,你在这里可以随意的使用其它被追踪的变量。

默认情况下,reaction 第一次是不会执行的,它会等待追踪函数的变化。只有当追踪函数返回的 data 发生变化,副作用才会被产生。通过把之前的 autorun 分割为追踪函数和效果函数,你可以对真正产生副作用的部分有更好的控制。

import { reaction } from "mobx";

class Router {
  @observable page = "main";

  setupNavigation() {
    reaction(
      () => this.page,
      page => {
        switch (page) {
          case "main":
            this.navigateToUrl("/");
            break;

          case "profile":
            this.navigateToUrl("/profile");
            break;

          case "admin":
            this.navigateToUrl("/admin");
            break;
        }
      }
    );
  }

  navigateToUrl(url) {
    /* ... */
  }
}

在上面的示例中,当我加载 main 页面的时候,我不想要触发导航。这是一个使用 reaction 的绝佳示例。只有当 Router 类中的 page 属性发生变化,才会导航到指定的 url。

以上是一个非常简单的路由功能,只包含了几个固定的页面。你可以通过添加一个 pageURL 的 map 结构来增强这个路由的可拓展性。通过这种方式,路由(伴随着 URL 改变)变成了更改你 store 中的某个属性产生的副作用。

使用 when 来触发一次性的副作用

autorunreaction 维护的是长期的副作用。当你初始化应用时你可能会创建一次性的副作用并且会期望它们在应用的生命周期内起作用。

有件事我之前一直没有提到,autorunreaction 都会返回一个 disposer 函数。你可以触发 disposer 并且在任何时候取消那些副作用。

const disposer = autorun(() => {
  /* 这里是副作用,基于追踪的被观察变量 */
});

// .... 之后的某个时间
disposer(); // 取消 autorun

现在我们构建的应用有很多使用场景。你可能会仅仅想要在你的应用达到某个条件的时候去触发特定的副作用。同时你想要这些特定的副作用只出现一次,之后再也不出现。

让我们看一个具体的例子:比如说,你想要在用户达到一个里程碑的时候显示一条信息。这个里程碑对任何用户来说只会出现一次,所以你不想创建一个像 autorunreaction这样的长期维护的副作用。是时候拿出 when 这个 API 来完成这项工作了。

when 需要两个参数,和 reaction 类似。第一个参数(追踪函数)需要返回一个布尔值。当返回值为 true,when 方法的第二个参数(效果函数)会执行。最棒的部分是 when 方法在执行之后会自动 dispose。所以没必要再去定义 disposer 函数同时人工触发它。

when(
  () => this.reachedMilestone,
  () => {
    this.showMessage({ title: "Congratulations", message: "You did it!" });
  }
);

故意忽略的部分

虽然我只提到了 actionautorunreactionwhen 方法,还有一些 MobX 提供给我们的 API 可以用来处理更进阶的场景。因为大部分场景下 MobX 只需要使用上面提及的 API,所以我故意暂时忽略了剩下的那些 API。一旦你可以自如的运用上面这些方法,剩下的是非常容易理解和学习的。这些是根基,在开始建设先进和华丽的上层建筑之前,我们要把这些烂熟于心。

我可能会为高阶 API 单独写一篇文章。也许是 Part-4。:-)

功能强大的开发套件

到目前为止,我们已经看到过许多去追踪对象变化并且响应这些变化的技术。Mobx 实现了更高一层的抽象,让我们可以从更高的层级去思考,而不需要去担心追踪和响应变化的意外复杂性。

我们现在有一个依靠领域模型变化的地基,在这之上,我们可以构建健壮的系统。把所有在领域模型之外的部分都当做副作用,我们可以提供视觉反馈(UI),同时也可以提供像监控、数据分析、日志等等更多的其它功能活动。

未完待续…

在 Part 3,我们会看到很多示例,以便于我们去练习我们目前学到的东西。