You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中Mobx Observer变更未触发重渲染问题排查

问题排查与解决思路

首先明确:Mobx 和 Next.js 不存在兼容性问题,你的问题大概率是 Mobx 的使用方式有误,以下是最常见的几个排查点:

1. 组件未用 observer 包裹

Mobx 需要通过 observer 高阶组件标记组件,才能让组件自动响应状态变化。如果 Hero 组件没加这个包裹,哪怕状态更新了,组件也不会重渲染。

示例修正:

// Hero.tsx
import { observer } from 'mobx-react-lite'

// 用 observer 包裹组件
const Hero = observer(() => {
  const accountStore = /* 获取你的 Store 实例 */
  return <button>{accountStore.address}</button>
})

export default Hero

2. Store 状态未标记为可观察

AccountStore 里的 address 字段如果没有被 Mobx 标记为可观察对象,状态更新时不会被追踪,组件自然感知不到变化。

方式一:用 makeAutoObservable 自动标记(推荐)

// AccountStore.ts
import { makeAutoObservable } from 'mobx'

class AccountStore {
  address = ''

  constructor() {
    // 自动将所有属性标记为 observable,方法标记为 action
    makeAutoObservable(this)
  }

  login() {
    this.address = 'Hello World'
  }
}

// 导出单例实例,确保所有组件共用同一个 Store
export const accountStore = new AccountStore()

方式二:用 makeObservable 手动标记

// AccountStore.ts
import { makeObservable, observable, action } from 'mobx'

class AccountStore {
  address = ''

  constructor() {
    makeObservable(this, {
      address: observable, // 标记为可观察状态
      login: action // 标记为修改状态的动作
    })
  }

  login() {
    this.address = 'Hello World'
  }
}

export const accountStore = new AccountStore()

3. Store 实例未共享

如果 Navbar 和 Hero 组件各自创建了新的 AccountStore 实例,两者的状态完全独立,点击 Navbar 的按钮自然不会影响 Hero 的显示。

必须确保所有组件使用同一个 Store 实例:

  • 不要在组件内部 new AccountStore(),而是直接导入上面导出的单例 accountStore;
  • 或者用 React Context 全局注入 Store(适合多 Store 场景),示例如下:
// StoreProvider.tsx
import { createContext, useContext, useEffect, useState } from 'react'
import { AccountStore } from './AccountStore'

const StoreContext = createContext<AccountStore | null>(null)

export const StoreProvider = ({ children }: { children: React.ReactNode }) => {
  const [store, setStore] = useState<AccountStore | null>(null)

  // 只在客户端初始化 Store,避免 SSR 时重复创建
  useEffect(() => {
    setStore(new AccountStore())
  }, [])

  if (!store) return null

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

// 自定义 Hook 方便组件获取 Store
export const useStore = () => {
  const store = useContext(StoreContext)
  if (!store) throw new Error('useStore 必须在 StoreProvider 内部使用')
  return store
}

然后在 _app.tsx 里全局包裹:

import { StoreProvider } from '../stores/StoreProvider'

function MyApp({ Component, pageProps }) {
  return (
    <StoreProvider>
      <Component {...pageProps} />
    </StoreProvider>
  )
}

export default MyApp

组件内通过 useStore() 获取实例:

const Hero = observer(() => {
  const accountStore = useStore()
  return <button>{accountStore.address}</button>
})

4. 检查状态修改是否在 action 内

虽然 makeAutoObservable 会自动把方法标记为 action,但如果是直接在组件里修改状态(而非调用 Store 的方法),需要用 runInAction 包裹:

// 错误示例:直接修改状态
const Navbar = () => {
  const accountStore = useStore()
  return <button onClick={() => accountStore.address = 'Hello World'}>Do Stuff</button>
}

// 正确示例:用 runInAction 包裹
import { runInAction } from 'mobx'

const Navbar = () => {
  const accountStore = useStore()
  return (
    <button onClick={() => {
      runInAction(() => {
        accountStore.address = 'Hello World'
      })
    }}>Do Stuff</button>
  )
}

优先推荐调用 Store 内定义的 login 方法修改状态,这样更符合 Mobx 的规范。

内容的提问来源于stack exchange,提问作者Ali Gasimzade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:45:40