项目结构 #

良好的项目结构是构建可维护 MobX 应用的基础。本文档介绍 MobX 项目的推荐组织方式。

目录结构 #

基本结构 #

text
src/
├── stores/              # MobX stores
│   ├── index.js        # 统一导出
│   ├── RootStore.js    # 根 Store
│   ├── UserStore.js    # 用户相关
│   ├── TodoStore.js    # Todo 相关
│   └── UIStore.js      # UI 状态
├── components/          # React 组件
│   ├── common/         # 通用组件
│   ├── user/           # 用户相关组件
│   └── todo/           # Todo 相关组件
├── hooks/              # 自定义 Hooks
├── services/           # API 服务
├── utils/              # 工具函数
├── App.jsx
└── main.jsx

功能模块结构 #

text
src/
├── modules/
│   ├── user/
│   │   ├── store/
│   │   │   ├── UserStore.js
│   │   │   └── index.js
│   │   ├── components/
│   │   │   ├── UserProfile.jsx
│   │   │   └── UserList.jsx
│   │   ├── services/
│   │   │   └── userService.js
│   │   └── index.js
│   ├── todo/
│   │   ├── store/
│   │   │   ├── TodoStore.js
│   │   │   └── index.js
│   │   ├── components/
│   │   │   ├── TodoList.jsx
│   │   │   └── TodoItem.jsx
│   │   └── index.js
│   └── index.js
├── stores/
│   └── RootStore.js
├── components/
│   └── common/
├── App.jsx
└── main.jsx

Store设计 #

单一Store模式 #

适用于小型应用:

javascript
// stores/AppStore.js
import { makeAutoObservable } from 'mobx';

class AppStore {
  // 用户状态
  user = null;
  isLoggedIn = false;

  // Todo 状态
  todos = [];
  filter = 'all';

  // UI 状态
  loading = false;
  error = null;

  constructor() {
    makeAutoObservable(this);
  }

  // 用户相关方法
  login(credentials) { }
  logout() { }

  // Todo 相关方法
  addTodo(title) { }
  removeTodo(id) { }

  // UI 相关方法
  setLoading(loading) { }
  setError(error) { }
}

export default new AppStore();

多Store模式 #

适用于中大型应用:

javascript
// stores/UserStore.js
import { makeAutoObservable, runInAction } from 'mobx';

class UserStore {
  user = null;
  token = null;
  loading = false;

  constructor(rootStore) {
    this.rootStore = rootStore;
    makeAutoObservable(this);
  }

  async login(credentials) {
    this.loading = true;
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials)
      });
      const data = await response.json();
      runInAction(() => {
        this.user = data.user;
        this.token = data.token;
        this.loading = false;
      });
    } catch (error) {
      runInAction(() => {
        this.loading = false;
      });
      throw error;
    }
  }

  logout() {
    this.user = null;
    this.token = null;
  }

  get isLoggedIn() {
    return this.user !== null;
  }
}

export default UserStore;
javascript
// stores/TodoStore.js
import { makeAutoObservable } from 'mobx';

class TodoStore {
  todos = [];
  filter = 'all';

  constructor(rootStore) {
    this.rootStore = rootStore;
    makeAutoObservable(this);
  }

  addTodo(title) {
    this.todos.push({
      id: Date.now(),
      title,
      completed: false
    });
  }

  removeTodo(id) {
    this.todos = this.todos.filter(t => t.id !== id);
  }

  get filteredTodos() {
    switch (this.filter) {
      case 'completed':
        return this.todos.filter(t => t.completed);
      case 'active':
        return this.todos.filter(t => !t.completed);
      default:
        return this.todos;
    }
  }
}

export default TodoStore;

RootStore模式 #

统一管理所有 Store:

javascript
// stores/RootStore.js
import UserStore from './UserStore';
import TodoStore from './TodoStore';
import UIStore from './UIStore';

class RootStore {
  constructor() {
    this.userStore = new UserStore(this);
    this.todoStore = new TodoStore(this);
    this.uiStore = new UIStore(this);
  }
}

export default new RootStore();
javascript
// stores/index.js
export { default as rootStore } from './RootStore';
export { default as userStore } from './RootStore'.userStore;
export { default as todoStore } from './RootStore'.todoStore;

Store通信 #

通过RootStore #

javascript
class TodoStore {
  constructor(rootStore) {
    this.rootStore = rootStore;
  }

  addTodo(title) {
    // 访问其他 store
    if (!this.rootStore.userStore.isLoggedIn) {
      this.rootStore.uiStore.showError('Please login first');
      return;
    }

    this.todos.push({ title });
  }
}

通过依赖注入 #

javascript
// stores/TodoStore.js
class TodoStore {
  constructor({ userStore, uiStore }) {
    this.userStore = userStore;
    this.uiStore = uiStore;
    makeAutoObservable(this);
  }
}

// stores/RootStore.js
class RootStore {
  constructor() {
    this.userStore = new UserStore();
    this.uiStore = new UIStore();
    this.todoStore = new TodoStore({
      userStore: this.userStore,
      uiStore: this.uiStore
    });
  }
}

React集成 #

使用Context #

javascript
// contexts/StoreContext.js
import React from 'react';
import rootStore from '../stores';

export const StoreContext = React.createContext(rootStore);

export const useStore = () => React.useContext(StoreContext);

// 使用
const Counter = observer(() => {
  const store = useStore();
  return <div>{store.counterStore.count}</div>;
});

Provider模式 #

javascript
// providers/StoreProvider.jsx
import React from 'react';
import { StoreContext } from '../contexts/StoreContext';
import RootStore from '../stores/RootStore';

export const StoreProvider = ({ children }) => {
  const store = React.useMemo(() => new RootStore(), []);
  return (
    <StoreContext.Provider value={store}>
      {children}
    </StoreContext.Provider>
  );
};

// App.jsx
import { StoreProvider } from './providers/StoreProvider';

function App() {
  return (
    <StoreProvider>
      <Main />
    </StoreProvider>
  );
}

服务层 #

API服务 #

javascript
// services/api.js
class ApiService {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }

  async request(endpoint, options = {}) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      headers: {
        'Content-Type': 'application/json',
        ...options.headers
      },
      ...options
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return response.json();
  }

  get(endpoint) {
    return this.request(endpoint);
  }

  post(endpoint, data) {
    return this.request(endpoint, {
      method: 'POST',
      body: JSON.stringify(data)
    });
  }
}

export default new ApiService('/api');

Store使用服务 #

javascript
// stores/UserStore.js
import { makeAutoObservable, flow } from 'mobx';
import api from '../services/api';

class UserStore {
  users = [];
  loading = false;

  constructor() {
    makeAutoObservable(this);
  }

  fetchUsers = flow(function* () {
    this.loading = true;
    try {
      this.users = yield api.get('/users');
    } finally {
      this.loading = false;
    }
  });

  createUser = flow(function* (userData) {
    const user = yield api.post('/users', userData);
    this.users.push(user);
    return user;
  });
}

export default new UserStore();

完整示例 #

项目结构 #

text
src/
├── stores/
│   ├── RootStore.js
│   ├── UserStore.js
│   ├── TodoStore.js
│   └── index.js
├── services/
│   ├── api.js
│   ├── userService.js
│   └── todoService.js
├── contexts/
│   └── StoreContext.js
├── providers/
│   └── StoreProvider.jsx
├── hooks/
│   └── useStore.js
├── components/
│   ├── common/
│   │   ├── Button.jsx
│   │   └── Input.jsx
│   ├── user/
│   │   ├── UserProfile.jsx
│   │   └── UserList.jsx
│   └── todo/
│       ├── TodoList.jsx
│       └── TodoItem.jsx
├── App.jsx
└── main.jsx

入口文件 #

javascript
// main.jsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { StoreProvider } from './providers/StoreProvider';
import App from './App';

createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <StoreProvider>
      <App />
    </StoreProvider>
  </React.StrictMode>
);

总结 #

模式 适用场景 优点 缺点
单一Store 小型应用 简单直接 难以维护
多Store 中大型应用 模块化 需要协调
RootStore 企业应用 统一管理 稍复杂

最佳实践:

  • 小型应用:使用单一 Store
  • 中大型应用:使用 RootStore 模式
  • 功能模块化:按功能划分 Store
  • 服务层分离:API 调用放在服务层
  • Context 注入:使用 React Context 提供 Store

继续学习 性能优化,了解 MobX 应用的性能优化技巧。

最后更新:2026-03-28