在 Nextjs 中使用 mobx| 青训营笔记

1,007 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天。因为我们小组采用 mobx 作为这次大作业的状态管理库,因此本篇文章主要来讨论下在 Nextjs 中 mobx 的相关配置。

仓库地址: github.com/Bocchi-Deve…

mobx 介绍

MobX 是一个身经百战的库,它通过运用透明的函数式响应编程使状态管理变得简单和可扩展。并且它对数据的变更和使用都会在运行时被追踪到,并构成一个截取所有状态和输出之间关系的依赖树。这样保证了那些依赖于状态的计算只有在真正需要时才会运行,就像 React 组件一样。无需使用记忆化或选择器之类容易出错的次优技巧来对组件进行手动优化,使用起来很方便。

在 Nextjs 中使用

因为 Nextjs 采用的服务端渲染,如果用传统方式配置的话,可能会发生内存泄漏,我们应该在服务端的时候开启静态渲染模式。

import { enableStaticRendering } from "mobx-react-lite";
enableStaticRendering(typeof window === "undefined");

综合上述,我的是这样配置的

import { configure } from 'mobx'
import { enableStaticRendering } from 'mobx-react-lite'
import type { ReactNode } from 'react'
import React, { createContext, useContext } from 'react'

import { isClientSide, isDev, isServerSide } from '~/utils/env'

import { RootStore } from '../store/root-store'

enableStaticRendering(isServerSide())

configure({
  useProxies: 'always',
})

let $store: RootStore
const StoreContext = createContext<RootStore | undefined>(undefined)
StoreContext.displayName = 'StoreContext'

export function useRootStore() {
  const context = useContext(StoreContext)
  if (context === undefined) {
    throw new Error('useRootStore must be used within RootStoreProvider')
  }

  return context
}
export const store = initializeStore()
export function RootStoreProvider({ children }: { children: ReactNode }) {
  if (isDev && isClientSide() && !window.store) {
    Object.defineProperty(window, 'store', {
      get() {
        return store
      },
    })
  }

  return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
}

function initializeStore(): RootStore {
  const _store = $store ?? new RootStore()

  // For SSG and SSR always create a new store
  if (typeof window === 'undefined') return _store
  // Create the store once in the client
  if (!$store) $store = _store

  return _store
}

同时我们可以创建一个 RootStore,来集中式管理不同的 store。

import AppUIStore from "./app";
import PostStore from "./post";

export interface RootStore {
  appUIStore: AppUIStore
  postStore: PostStore
}
export class RootStore {
  constructor() {
    this.appUIStore = new AppUIStore()
    this.postStore = new PostStore()
  }

  get appStore() {
    return this.appUIStore
  }
}