性能优化 #
MobX 本身已经非常高效,但了解一些优化技巧可以帮助你构建更高性能的应用。
组件优化 #
使用observer包装 #
javascript
import { observer } from 'mobx-react-lite';
// 正确:使用 observer
const TodoItem = observer(({ todo }) => (
<li>{todo.title}</li>
));
// 错误:不使用 observer
const TodoItem = ({ todo }) => (
<li>{todo.title}</li>
);
组件拆分 #
javascript
// 不好:一个大组件
const TodoList = observer(() => (
<div>
<h1>Todo List</h1>
<ul>
{store.todos.map(todo => (
<li key={todo.id}>
<span>{todo.title}</span>
<span>{todo.completed ? 'Done' : 'Pending'}</span>
<button onClick={() => store.toggle(todo.id)}>Toggle</button>
<button onClick={() => store.remove(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
));
// 好:拆分成小组件
const TodoItem = observer(({ todo }) => (
<li>
<span>{todo.title}</span>
<span>{todo.completed ? 'Done' : 'Pending'}</span>
<button onClick={() => store.toggle(todo.id)}>Toggle</button>
<button onClick={() => store.remove(todo.id)}>Delete</button>
</li>
));
const TodoList = observer(() => (
<div>
<h1>Todo List</h1>
<ul>
{store.todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
</div>
));
使用Observer组件 #
javascript
import { Observer } from 'mobx-react-lite';
// 精确控制更新范围
const UserProfile = () => (
<div>
<h1>{user.name}</h1>
<Observer>
{() => <span>Status: {user.status}</span>}
</Observer>
</div>
);
避免不必要的追踪 #
javascript
// 不好:追踪整个对象
const UserCard = observer(({ user }) => (
<div>{JSON.stringify(user)}</div>
));
// 好:只追踪需要的属性
const UserCard = observer(({ user }) => (
<div>{user.name}</div>
));
计算值优化 #
使用computed缓存 #
javascript
class Store {
items = [];
constructor() {
makeAutoObservable(this);
}
// 好:使用 computed 缓存
get filteredItems() {
return this.items.filter(item => item.active);
}
get sortedItems() {
return [...this.filteredItems].sort((a, b) => a.order - b.order);
}
}
computed.struct #
javascript
class Store {
x = 0;
y = 0;
constructor() {
makeAutoObservable(this, {
position: computed.struct
});
}
// 结构相同不触发更新
get position() {
return { x: this.x, y: this.y };
}
}
避免昂贵的计算 #
javascript
class Store {
largeArray = [];
// 不好:每次都计算
get expensiveValue() {
return this.largeArray.reduce((acc, item) => {
// 复杂计算...
return acc;
}, 0);
}
// 好:缓存结果,手动更新
cachedValue = 0;
updateCache() {
this.cachedValue = this.largeArray.reduce((acc, item) => {
return acc;
}, 0);
}
}
批量更新 #
使用action #
javascript
class Store {
a = 0;
b = 0;
c = 0;
// 好:action 自动批量更新
updateAll() {
this.a = 1;
this.b = 2;
this.c = 3;
// 只触发一次渲染
}
}
transaction(已弃用) #
javascript
// 不推荐:使用 action 替代
import { transaction } from 'mobx';
transaction(() => {
store.a = 1;
store.b = 2;
});
列表优化 #
使用key #
javascript
// 好:使用稳定的 key
const TodoList = observer(() => (
<ul>
{store.todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
));
// 不好:使用索引作为 key
const TodoList = observer(() => (
<ul>
{store.todos.map((todo, index) => (
<TodoItem key={index} todo={todo} />
))}
</ul>
));
虚拟列表 #
javascript
import { observer } from 'mobx-react-lite';
import { FixedSizeList } from 'react-window';
const VirtualList = observer(() => (
<FixedSizeList
height={400}
itemCount={store.items.length}
itemSize={50}
>
{({ index, style }) => (
<div style={style}>
{store.items[index].name}
</div>
)}
</FixedSizeList>
));
分页加载 #
javascript
class Store {
allItems = [];
pageSize = 20;
currentPage = 1;
get visibleItems() {
const start = (this.currentPage - 1) * this.pageSize;
return this.allItems.slice(start, start + this.pageSize);
}
loadMore() {
this.currentPage++;
}
}
响应式优化 #
精确追踪 #
javascript
import { reaction } from 'mobx';
// 好:只追踪特定属性
reaction(
() => store.user.name,
(name) => {
console.log('Name changed:', name);
}
);
// 不好:追踪整个对象
reaction(
() => store.user,
(user) => {
console.log('User changed:', user);
}
);
使用reaction替代autorun #
javascript
// autorun:追踪所有访问的状态
autorun(() => {
console.log(store.a, store.b);
});
// reaction:只追踪指定的状态
reaction(
() => store.a,
(a) => {
console.log('A changed:', a);
}
);
清除reaction #
javascript
// 记得清除不再需要的 reaction
useEffect(() => {
const dispose = reaction(
() => store.count,
(count) => {
console.log(count);
}
);
return () => dispose();
}, []);
内存优化 #
清除autorun和reaction #
javascript
class Store {
disposers = [];
constructor() {
makeAutoObservable(this);
// 保存清除函数
this.disposers.push(
autorun(() => {
// ...
})
);
this.disposers.push(
reaction(
() => this.count,
() => {
// ...
}
)
);
}
destroy() {
// 清除所有 reaction
this.disposers.forEach(dispose => dispose());
this.disposers = [];
}
}
避免内存泄漏 #
javascript
// 组件中
useEffect(() => {
const dispose = autorun(() => {
// ...
});
return () => dispose();
}, []);
// 类中
class Component {
componentDidMount() {
this.dispose = autorun(() => {
// ...
});
}
componentWillUnmount() {
if (this.dispose) {
this.dispose();
}
}
}
配置优化 #
configure选项 #
javascript
import { configure } from 'mobx';
configure({
// 强制使用 action
enforceActions: 'always',
// 禁止在 reaction 外访问 computed
computedRequiresReaction: true,
// 禁止直接修改 observable 值
reactionRequiresObservable: true,
// 禁止在 observable 外追踪
observableRequiresReaction: true
});
性能监控 #
使用spy #
javascript
import { spy } from 'mobx';
if (process.env.NODE_ENV === 'development') {
spy((event) => {
if (event.type === 'action') {
console.time(event.name);
}
if (event.type === 'reaction') {
console.timeEnd(event.name);
}
});
}
React DevTools #
javascript
import { observer } from 'mobx-react-lite';
// observer 会自动在 React DevTools 中显示组件名
const TodoItem = observer(function TodoItem({ todo }) {
return <li>{todo.title}</li>;
});
总结 #
| 优化点 | 方法 |
|---|---|
| 组件更新 | 使用 observer,拆分组件 |
| 计算缓存 | 使用 computed,computed.struct |
| 批量更新 | 使用 action |
| 列表渲染 | 使用 key,虚拟列表 |
| 内存管理 | 清除 reaction |
性能优化原则:
- 最小化追踪范围:只追踪需要的状态
- 合理拆分组件:细粒度更新
- 使用计算值缓存:避免重复计算
- 批量更新:减少渲染次数
- 及时清理:避免内存泄漏
继续学习 MobX与TypeScript,了解 TypeScript 集成。
最后更新:2026-03-28