前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React 进阶 - React Mobx

React 进阶 - React Mobx

作者头像
Cellinlab
发布2023-05-17 20:54:32
8270
发布2023-05-17 20:54:32
举报
文章被收录于专栏:Cellinlab's Blog

# Mobx 特性

# 观察者模式

Mobx 采用了一种'观察者模式'—— Observer,整个设计架构都是围绕 Observer 展开:

  • 在 mobx 的状态层,每一个需要观察的属性都会添加一个观察者,可以称之为 ObserverValue
  • 有了观察者,那么就需要向观察者中收集 listener ,mobx 中有一个 Reaction 模块,可以对一些行为做依赖收集,在 React 中,是通过劫持 render 函数执行行为,进行的依赖收集
  • 如何监听改变,用自定义存取器属性中的 getset ,来进行的依赖收集和更新派发,当状态改变,观察者会直接精确通知每个 listener

# 状态提升

在正常情况下,在 React 应用中使用 Mobx ,本质上 mobx 里面的状态,并不是存在 React 组件里面的,是在外部由一个个 mobx 的模块 model 构成,每一个 model 可以理解成一个对象,状态实质存在 model 中,model 状态通过 props 添加到组件中,可以用 mobx-react 中的 Provderinject 便捷获取它们,虽然 mobx 中响应式处理这些状态,但是不要试图直接修改 props 来促使更新,这样违背了 React Prop 单向数据流的原则。正确的处理方法,还是通过 model 下面的 action 方法,来改变状态,React 实质上调用的是 action 方法。

# 装饰器模式

为了建立观察者模式,便捷地获取状态 / 监听状态,mobx 很多接口都支持装饰器模式的写法,所以在 mobx 中,装饰器模式是最常用的写法:

代码语言:javascript
复制
class Root {
  @observable name = "Cell"
  @action setName(name) {
    this.name = name
  }
}

# 精确颗粒化收集

mobx 有一个重要特点,对于属性的依赖收集是精确的,颗粒化的:

代码语言:javascript
复制
class Root {
  // C 组件使用
  @observable object = {
    name: "Cell", // A 组件使用
    msg: "Hello World", // B 组件使用
  }
  @action setName(name) {
    this.object.name = name
  }
  @action setMsg(msg) {
    this.object.msg = msg
  }
  @action setObject(object) {
    this.object = object
  }
}

  • 对于 observable 处理过的属性,每一个属性都会有 ObserverValue ,比如上面的结构会产生三个 ObserverValue ,分别对应 objectnamemsg
  • 当上面通过 setName 改变 name 属性的时候,只有组件 A 会更新,
    • 也就是 name ObserverValue 只收集了用到 name 的依赖项 A 组件
  • 调用 setMsg 同理,只有组件 B 更新
    • msg ObserverValue 只收集了 B 组件的依赖
  • 当上面通过 setObject 改变 object 的时候,即使 object 里面 namemsg 的值没有变化,也会让组件 A ,组件 B ,组件 C ,全部渲染
    • objectObserver 同样收集了 nameObserverValuemsgObserverValue

# 引用类型处理

observable 对于引用数据类型,比如 ObjectArraySetMap 等,除了新建一个 observable 之外,还会做如下两点操作:

  • Proxy:会把原始对象用 Proxy 代理,Proxy 会精确响应原始对象的变化,比如增加属性——给属性绑定 ObserverValue ,删除属性——给属性解绑 ObserverValue
  • ObservableAdministration: 对于子代属性,会创建一个 ObservableAdministration,用于管理子代属性的 ObserverValue

对于外层 Root ,在 constructor 使用 makeObservable ,mobx 会默认给最外层的 Root 添加 ObservableAdministration

# Mobx 基本使用

# mobx 常用 API

把上述每一个 class 称之为一个模块,如上述 Root 就是一个模块。mobx 的 api 基本用于构建每一个响应式模块。

makeObservable

  • 在新版本 mobx 中,想要让整个模块变成可响应式的,那么需要在 constructor 调用 makeObservable
代码语言:javascript
复制
constructor() {
  makeObservable(this)
}

observable

  • 会给属性值加一个观察者对象,使其能变成可观察的,当属性值改变的时候,观察者会通知每一个依赖项
代码语言:javascript
复制
@observable name = "Cell"

action

  • 通过 action 包裹的函数,可以用来修改 mobx 中的状态
代码语言:javascript
复制
@action setName(name) {
  this.name = name
}

computed

  • 根据现有的状态或其它计算值衍生出的值
代码语言:javascript
复制
@observable price = 666
@observable count = 1
@computed get total() {
  return this.price * this.count
}

# mobx-react 常用 API

mobx-react 中的 api ,用于把 mobx 中的状态,提供给组件,并把组件也变成可观察的 —— mobx 状态改变,组件触发更新。

Provider

  • 用于把 mobx 的各个模块,用 Context 上下文形式,保存起来,供给组件使用
代码语言:javascript
复制
<Provider Root={Root}>
  <App />
</Provider>

inject

  • inject 高阶组件可以把 Provider 中的 mobx 模块,混入到组件的 props 中,所以就可以在组件中消费状态,或者调用改变状态的方法
代码语言:javascript
复制
@inject("Root")
class Index extends React.Component {}

observer

  • observer 高阶组件包装的组件,如果组件内部引入了 mobx 可观察属性值,当值改变的时候,会追溯到当前组件,促使当前组件更新
代码语言:javascript
复制
@observer
class Index extends React.Component {}

# 实践-实现状态共享

创建 Root 模块,用于保存全局的一些数据:

代码语言:javascript
复制
import { observable, action, makeObservable } from "mobx"

class Root {
  constructor() {
    makeObservable(this)
  }
  @observable info = {
    name: "Cell",
    age: 18,
  }
  @action setInfo(info) {
    this.info = info
  }
}
export default new Root()

根本组件注入状态:

代码语言:javascript
复制
import Root from "./mobx"

export default function Index() {
  return (
    <Provider Root={Root}>
      <Child />
    </Provider>
  )
}

使用状态:

代码语言:javascript
复制
const getUserInfo = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        name: "Cell",
        age: 18,
      })
    }, 1000)
  })
}

@inject("Root")
@observer
class Child extends React.Component {
  async componentDidMount() {
    const info = await getUserInfo()
    this.props.Root.setInfo(info)
  }
  render() {
    const { info } = this.props.Root
    return (
      <div>
        <p>name: {info.name}</p>
        <p>age: {info.age}</p>
      </div>
    )
  }
}

# 实践-实现组件通信

注册模块用于组件通信:

代码语言:javascript
复制
class Commui {
  constructor() {
    makeObservable(this)
  }
  @observable msgA = ""
  @observable msgB = ""
  @action setMsgA(msg) {
    this.msgA = msg
  }
  @action setMsgB(msg) {
    this.msgB = msg
  }
}
export default new Commui()

建立 A 、 B 组件实现通信功能:

代码语言:javascript
复制
@inject("Commui")
@observer
class CommponentA extends React.Component {
  state = {
    CompAsay: "",
  }
  render() {
    const { CompAsay } = this.state
    const { mesB } = this.props.Commui
    return (
      <div>
        CommponentA
        <div>from B:{mesB}</div>
        <input
          type="text"
          value={CompAsay}
          onChange={(e) => this.setState({ CompAsay: e.target.value })}
        />
        <button onClick={() => this.props.Commui.setMsgA(CompAsay)}>send</button>
      </div>
    )
  }
}

@inject("Commui")
@observer
class CommponentB extends React.Component {
  state = {
    CompBsay: "",
  }
  render() {
    const { CompBsay } = this.state
    const { mesA } = this.props.Commui
    return (
      <div>
        CommponentB
        <div>from A:{mesA}</div>
        <input
          type="text"
          value={CompBsay}
          onChange={(e) => this.setState({ CompBsay: e.target.value })}
        />
        <button onClick={() => this.props.Commui.setMsgB(CompBsay)}>send</button>
      </div>
    )
  }
}

# Mobx 流程分析和原理揭秘

可以从三个角度分析 mobx 和 mobx-react 整个流程:

  • 初始化: mobx 在初始化的时候,是如何处理 observable 可观察属性的
  • 依赖收集:通过 mobx-react 中的 observer ,如何收集依赖项,与 observable 建立起关系的
  • 派发更新:当改变可观察属性的值的时候,如何更新对应组件的

# 模块初始化

  1. 绑定状态-observable
  2. 激活状态-makeObservable
  3. 观察者属性管理者-ObservableAdministration

# 依赖收集

  1. 观察者-ObservableValue
  2. 注入模块-Providerinject
  3. 可观察组件-observer
  4. 反应器-Reaction

# 派发更新

# Mobx 与 Redux 区别

  • 在 Mobx 在上手程度上,要优于 Redux ,比如 Redux 想使用异步,需要配合中间价,流程比较复杂
  • Redux 对于数据流向更规范化,Mobx 中数据更加多样化,允许数据冗余
  • Redux 整体数据流向简单,Mobx 依赖于 ProxyObject.defineProperty 等,劫持属性 getset ,数据变化多样性
  • Redux 可拓展性比较强,可以通过中间件自定义增强 dispatch
  • 在 Redux 中,基本有一个 store ,统一管理 store 下的状态,在 mobx 中可以有多个模块,可以理解每一个模块都是一个 store ,相互之间是独立的
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/9/23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # Mobx 特性
    • # 观察者模式
      • # 状态提升
        • # 装饰器模式
          • # 精确颗粒化收集
            • # 引用类型处理
            • # Mobx 基本使用
              • # mobx 常用 API
                • # mobx-react 常用 API
                  • # 实践-实现状态共享
                    • # 实践-实现组件通信
                    • # Mobx 流程分析和原理揭秘
                      • # 模块初始化
                        • # 依赖收集
                          • # 派发更新
                          • # Mobx 与 Redux 区别
                          相关产品与服务
                          消息队列 TDMQ
                          消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档