乐闻世界logo
搜索文章和话题

MobX 性能优化的最佳实践有哪些?

2月21日 15:49

MobX 本身已经是一个高性能的状态管理库,但在实际应用中,仍然有一些优化技巧可以进一步提升性能。以下是 MobX 性能优化的最佳实践:

1. 合理使用 computed

computed 的缓存机制

computed 属性会自动缓存结果,只在依赖项变化时重新计算:

javascript
class Store { @observable firstName = 'John'; @observable lastName = 'Doe'; @observable age = 30; @computed get fullName() { console.log('Computing fullName'); return `${this.firstName} ${this.lastName}`; } @computed get info() { console.log('Computing info'); return `${this.fullName}, ${this.age} years old`; } } // 第一次访问会计算 console.log(store.info); // Computing fullName, Computing info // 再次访问,使用缓存 console.log(store.info); // 无输出 // 修改 age,只重新计算 info store.age = 31; console.log(store.info); // Computing info

避免在 computed 中产生副作用

javascript
// 错误:在 computed 中产生副作用 @computed get badComputed() { console.log('Side effect!'); // 不应该在 computed 中 fetch('/api/data'); // 不应该在 computed 中 return this.data; } // 正确:computed 应该是纯函数 @computed get goodComputed() { return this.data.filter(item => item.active); }

2. 优化 observable 的使用

只对需要追踪的状态使用 observable

javascript
// 不好的做法:所有状态都是 observable class Store { @observable config = { apiUrl: 'https://api.example.com', timeout: 5000, retries: 3 }; } // 好的做法:只对会变化的状态使用 observable class Store { config = { apiUrl: 'https://api.example.com', timeout: 5000, retries: 3 }; @observable data = []; @observable loading = false; }

使用 shallow 或 deep 控制可观察深度

javascript
import { observable, deep, shallow } from 'mobx'; // 深度可观察(默认) const deepStore = observable({ user: { profile: { name: 'John' } } }); // 浅层可观察 const shallowStore = observable.shallow({ users: [ { name: 'John' }, { name: 'Jane' } ] }); // 只有数组本身是可观察的,数组中的对象不是

3. 批量更新状态

使用 runInAction 批量更新

javascript
// 不好的做法:多次触发更新 @action badUpdate() { this.count++; this.name = 'New Name'; this.age++; } // 好的做法:批量更新 @action goodUpdate() { runInAction(() => { this.count++; this.name = 'New Name'; this.age++; }); }

使用 transaction(MobX 4/5)

javascript
import { transaction } from 'mobx'; transaction(() => { store.count++; store.name = 'New Name'; store.age++; });

4. 优化组件渲染

使用 observer 只在需要的地方

javascript
// 不好的做法:所有组件都用 observer @observer const Header = () => <h1>My App</h1>; @observer const Footer = () => <footer>© 2024</footer>; // 好的做法:只在需要响应状态变化的组件上使用 observer const Header = () => <h1>My App</h1>; const Footer = () => <footer>© 2024</footer>; @observer const Counter = () => <div>{store.count}</div>;

拆分组件以减少依赖

javascript
// 不好的做法:组件依赖太多状态 @observer const BadComponent = () => { return ( <div> <div>{store.user.name}</div> <div>{store.user.email}</div> <div>{store.settings.theme}</div> <div>{store.settings.language}</div> <div>{store.data.length}</div> </div> ); }; // 好的做法:拆分为多个组件 @observer const UserInfo = () => { return ( <div> <div>{store.user.name}</div> <div>{store.user.email}</div> </div> ); }; @observer const Settings = () => { return ( <div> <div>{store.settings.theme}</div> <div>{store.settings.language}</div> </div> ); }; @observer const DataCount = () => { return <div>{store.data.length}</div>; };

使用 React.memo 配合 observer

javascript
const PureComponent = React.memo(observer(() => { return <div>{store.count}</div>; }));

5. 避免在 render 中创建新对象

javascript
// 不好的做法:每次渲染都创建新对象 @observer const BadComponent = () => { const style = { color: 'red' }; const handleClick = () => console.log('clicked'); return <div style={style} onClick={handleClick}>{store.count}</div>; }; // 好的做法:在组件外部定义 const style = { color: 'red' }; const handleClick = () => console.log('clicked'); @observer const GoodComponent = () => { return <div style={style} onClick={handleClick}>{store.count}</div>; };

6. 使用 trace 调试性能问题

javascript
import { trace } from 'mobx'; // 追踪 computed 的依赖 trace(store.fullName); // 追踪 reaction 的依赖 autorun(() => { console.log(store.count); }, { name: 'myReaction' }); // 追踪组件的渲染 @observer class MyComponent extends React.Component { render() { trace(true); // 追踪组件渲染 return <div>{store.count}</div>; } }

7. 使用 configure 优化配置

javascript
import { configure } from 'mobx'; configure({ // 强制所有状态修改都在 action 中 enforceActions: 'always', // 使用 Proxy(如果可用) useProxies: 'ifavailable', // computed 需要 reaction 才能计算 computedRequiresReaction: false, // 禁用不需要的警告 isolateGlobalState: true });

8. 优化数组操作

使用 splice 而不是重新赋值

javascript
// 不好的做法:重新赋值整个数组 @action badAddItem(item) { this.items = [...this.items, item]; } // 好的做法:使用 splice @action goodAddItem(item) { this.items.push(item); }

使用 replace 批量替换

javascript
@action replaceItems(newItems) { this.items.replace(newItems); }

9. 使用 reaction 替代 autorun

javascript
// 不好的做法:autorun 会立即执行 autorun(() => { console.log(store.count); }); // 好的做法:reaction 提供更细粒度的控制 reaction( () => store.count, (count) => { console.log(count); }, { fireImmediately: false } );

10. 使用 when 处理一次性条件

javascript
// 不好的做法:使用 autorun 处理一次性条件 autorun(() => { if (store.data.length > 0) { processData(store.data); } }); // 好的做法:使用 when when( () => store.data.length > 0, () => processData(store.data) );

11. 避免循环依赖

javascript
// 不好的做法:循环依赖 class StoreA { @observable value = 0; @computed get doubled() { return storeB.value * 2; } } class StoreB { @observable value = 0; @computed get doubled() { return storeA.value * 2; } } // 好的做法:避免循环依赖 class Store { @observable valueA = 0; @observable valueB = 0; @computed get doubledA() { return this.valueA * 2; } @computed get doubledB() { return this.valueB * 2; } }

12. 清理不需要的 reaction

javascript
// 在组件卸载时清理 reaction useEffect(() => { const dispose = autorun(() => { console.log(store.count); }); return () => { dispose(); // 清理 reaction }; }, []);

13. 使用 MobX DevTools 分析性能

MobX DevTools 提供了强大的性能分析功能:

  • 查看依赖关系图
  • 监控状态变化
  • 分析渲染性能
  • 调试 computed 和 reaction

14. 避免过度追踪

javascript
// 不好的做法:在循环中访问 observable @observer const BadComponent = () => { return ( <div> {store.items.map(item => ( <div key={item.id}> {item.name} - {item.value} </div> ))} </div> ); }; // 好的做法:使用 computed 预处理数据 class Store { @observable items = []; @computed get itemDisplayData() { return this.items.map(item => ({ id: item.id, display: `${item.name} - ${item.value}` })); } } @observer const GoodComponent = () => { return ( <div> {store.itemDisplayData.map(item => ( <div key={item.id}>{item.display}</div> ))} </div> ); };

15. 使用 makeAutoObservable 简化代码

javascript
// MobX 6 推荐使用 makeAutoObservable class Store { count = 0; firstName = 'John'; lastName = 'Doe'; constructor() { makeAutoObservable(this); } get fullName() { return `${this.firstName} ${this.lastName}`; } increment() { this.count++; } }

总结

MobX 性能优化的关键点:

  1. 合理使用 computed 的缓存机制
  2. 只对需要追踪的状态使用 observable
  3. 批量更新状态减少触发次数
  4. 优化组件渲染,减少不必要的重新渲染
  5. 避免在 render 中创建新对象
  6. 使用 trace 调试性能问题
  7. 清理不需要的 reaction
  8. 避免循环依赖和过度追踪

遵循这些最佳实践,可以构建高性能的 MobX 应用。

标签:Mobx