项目结构 #
良好的项目结构是构建可维护 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