这篇文章上次修改于 1181 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

最近在编写一套基于 React + NextJS 技术栈的网站,由于需要考虑到 用户登录 与 权限验证,不同的用户会呈现不一样的内容。若要实现这样的功能,肯定是需要一个“全局变量”才方便啊。需要使用到它的一个简单例子,大致如下:

  • 未登录:无法访问,提示需要登录
  • 已登录,非 VIP:提示需要 VIP
  • 已登录,是 VIP:正常访问内容

安装

若要在现有的 NextJS 项目中使用,首先打开终端,定位到项目目录下,执行 yarn add mobx mobx-react 安装。这里我用的是 Mobx 的最新版本 6.0.4,你可以在 package.json 看到你已安装的版本。

{
  "dependencies": {
    "mobx": "^6.0.4",
    "mobx-react": "^7.0.5"
  }
}

概念

就我目前的项目复杂程度可言,我只需要一个很基础的用法,分别是「读取」和「获取」就可以了。以下是我结合官方文档的 Demo 写的一个案例:

// store/user.js

// 自动根据对象类型设置监听对象和 Action
import { makeAutoObservable } from "mobx";

class User_Info {
  // 被监听的对象
  session = {
    access: "",
    refresh: ""
  }

  // 初始化一个 Mobx 并监听数据
  constructor() {
    makeAutoObservable(this);
  }
}

const store = new User_Info();

export default store;

读取

读取数据就简单了,使用模块的方式,导出一个已经初始化的 class 对象,再通过索引值就可以实现。

import userinfo from "@/store/userinfo";
import { observer } from "mobx-react-lite";

// 你的组件,这样就可以根据 Mobx 的值自动化
const HeadAction = observer((props) => {
  return (
    <div className="head-action">
      {props.session.access ? <Link href="/profile">Profile</Link> : <Link href="/auth/login">Login</Link>}
    </div>
  )
});

function Header(){
  return (
    <div className="head-action">
      <HeadAction user={userinfo}></HeadAction>
    </div>
  )
}

export default Header;

写入

而写入需要在 class 里面编写一个 action,该 Action 除了能修改值以外,也是想让需要根据值产生「页面元素重绘」的一个重要步骤。

// store/user.js

// 自动根据对象类型设置监听对象和 Action
import { makeAutoObservable } from "mobx";

class User_Info {
  // 被监听的对象
  session = {
    access: "",
    refresh: ""
  }

  // 初始化一个 Mobx 并监听数据
  constructor() {
    makeAutoObservable(this);
  }

  // 修改信息的 Action
  setData(value){
    let item;

    for(item in value){
      this.session[item] = value[item];
    }
  }

  // 重置信息的 Action
  removeData(){
    this.session.access = "";
    this.session.refresh = "";
  }
}

const store = new User_Info();

export default store;

这样就可以在其他页面中调用 action,进行修改和重置的操作了。

useEffects(() => {
  // 清除数据
  userinfo.removeData();
})

计算属性

看到这里,是否感觉其实还蛮简单的?Mobx 还有一个常用的东西,叫做 computed 函数,它的用法类似 Vue2 的 Computed 计算属性。依旧是在 Class 里面定义,在前面加个 get 就可以了。

// 根据现有的值,确定是否登录
// 根据数据内容返回布尔值
get logined(){
  if(this.session.access){
    return true;
  }
  else{
    return false;
  }
}

// 使用时,并不需要带括号
// userinfo.logined

中文文档踩坑

研究 Mobx 期间,我其实首先看的是「中文版本」的文档。该文档对应的最新版本是 5x,而官方文档使用的是 6x 了。看了下对应的 维护仓库,发现上次更新已经是 2 年前了。那么中文文档和英文文档有什么差异呢?主要在于 Mobx 对象的定义方式上,新版和旧版有所出入。

旧版文档使用了一个叫做「修饰器」(Decorators)的东西,也就是下面这个带上了 @ 的定义方式。

import { observable } from "mobx";

class Todo {
    id = Math.random();
    @observable title = "";
    @observable finished = false;
}

而我的 Playground 项目并没有使用 TypeScript,因此无法使用,这对我的学习产生了很大的阻碍。

等我看到了官方 最新版本 的文档,才得知这已经不是官方推荐的写法了。

If you have used MobX before, or if you followed online tutorials, you probably saw MobX with decorators like @observable. In MobX 6, we have chosen to move away from decorators by default, for maximum compatibility with standard JavaScript. They can still be used if you enable them though.

根据最新文档的写法,并结合 makeAutoObservable 来使用,也能大大减少有关定义相关的代码。

至此,以上就是我初入 Mobx 所理解的一些概念和使用方法。如有疑问,欢迎留言评论交流~

参考

《Mobx 官方文档》(英文)