react hook 风格下不再使用class类的形式定义组件,也就不再适用mobx以前版本的装饰器语法。

以下分享 reack hook 语法风格下使用 mobx v6 版本的状态管理配置使用方式。

相关依赖版本:
"react": "^17.0.2",
"mobx": "^6.3.2",
"mobx-react-lite": "^3.2.2",

一、mobx

mobx 是 react 生态中常用的状态管理插件之一,特点是配置及使用方式比较简便,方式上和 vuex 有些相似。
官方中文文档:https://zh.mobx.js.org/react-integration.html

mobx-react-lite 是配合 react 使用的一个轻量化插件,只支持函数式组件,适合 react hook。

官方已不建议使用装饰器语法,主要原因是js装饰器在现在的 ES 规范中并不成熟(目前在stage-2提案阶段且迟迟无法推进),而且引入装饰器语法也会增加打包后的代码体积。这里也将完全放弃装饰器方式。

以下配置使用 react context 方式来传递数据,这也是官方推荐的方式。因为直接引用store原始数据在有多个module模块下可能会使引用变得杂乱,管理维护困难且不利于单元测试。

二、配置

先安装依赖:npm i -S mobx mobx-react-lite

1、配置 store/model

创建 根store src/store/index.js

import User from './modules/user'

export default {
  userStore: new User(),
}

创建 User模块 src/store/modules/user.js

import { makeAutoObservable } from 'mobx'

export default class User {
  constructor () {
    /**
     * state
     */
    this.ticket = '' // 登录凭证ticket

    makeAutoObservable(this)
  }

  /**
   * computed
   */
  get isLogin () {
    return !!this.ticket
  }

  /**
   * action
   */
  setTicket (val) {
    this.ticket = val || ''
  }
}
  • makeAutoObservable 会将你定义的数据自动转化为相应类型的可观察对象,例如 constructor 里定义的转化为 state,get 定义的函数转化为 computed,非 get 定义的函数转化为 action。

2、配置 context

创建 store 状态管理的 context 文件 src/contexts/storeContext.js

import React from 'react'
import store from '@/store'

const storeContext = React.createContext(store)

export default storeContext
  • createContext函数参数为默认值,ts下需要。
  • 使用 react context 向下级传递,来共享全局可观察数据。
  • 引用方式在下面。

3、配置 hook

创建 store 状态管理的 hook 文件 src/hooks/storeHook.js

import { useContext } from 'react'
import StoreContext from '@/contexts/storeContext'
import { observer } from 'mobx-react-lite'

function useStore () {
  const store = useContext(StoreContext)
  return store
}

export {
  observer,
  useStore,
}
  • 导出的 useStore 用于获取store数据。后续页面或组件都通过引用这个hook来获取store数据。
  • 导出的 observer 用于监听store数据的改变,同步到组件数据中。后续页面或组件如需要响应store数据的变化,就引用它包裹一下页面或组件的默认导出函数即可。
  • 这里将 mobx-react-lite 的 observer 在hook里导出是为了使用方便,一个hook就能引入全部所需。

4、引入 store

项目入口文件 src/index.js 里引用:

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import StoreContext from '@/contexts/storeContext'
import store from '@/store'

ReactDOM.render(
  <React.StrictMode>
    <StoreContext.Provider value={store}>
      <App />
    </StoreContext.Provider>
  </React.StrictMode>,
  document.getElementById('root')
)

三、使用

1、获取/响应 store 数据

示例组件 src/App.jsx

import { useStore, observer } from '@/hooks/storeHook'

function App () {
  const { userStore } = useStore()
  
  function onSetStore () {
    userStore.setTicket('ttt')
  }
  
  return (
    <div>
      <p>ticket:{userStore.ticket}</p>

	  <button onClick={onSetStore}>修改store中的ticket</button>
    </div>
  )
}

export default observer(App)
  • 通过自定义的 storeHook 来使用 store 的数据。
  • 如果只是获取一次 store 的数据而无需响应 store 数据的变化,只需要引用 useStore 即可。
  • 如果需要响应 store 数据的变化,即时更新到视图,就需要引用 observer,然后包裹一下该页面或组件的默认导出函数,即可实现响应式。

2、普通 js 中使用

  • 普通js,就是非页面或组件的js里,没办法使用hook。
  • 不过其实使用hook方式的目的就是能实现store数据的响应式。
  • 普通js里不需要数据响应式,直接引入原始store文件就行。

示例 js src/http/axios.js

import axios from 'axios'
import store from '@/store'

const { userStore } = store

const service = axios.create()

service.interceptors.request.use(
  (config) => {
    config.headers = {
      ...config.headers,
      ticket: userStore.ticket,
    }
    return config
  },
  err => {
    Promise.reject(err)
  }
)

export default service
  • 以上实现一个简易的axios请求配置,实现效果就是在请求头headers里统一携带ticket参数,参数值从src/store/index.js文件里直接取。
  • 如要修改store数据用法也一样,调用 userStore.setTicket() 即可。

四、总结

通过这种方式配置后,状态管理的使用将变得简单高效,完美兼容 react hook 语法,和 ts 配合也不再有障碍。

Logo

前往低代码交流专区

更多推荐