性能优化 #

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

性能优化原则:

  1. 最小化追踪范围:只追踪需要的状态
  2. 合理拆分组件:细粒度更新
  3. 使用计算值缓存:避免重复计算
  4. 批量更新:减少渲染次数
  5. 及时清理:避免内存泄漏

继续学习 MobX与TypeScript,了解 TypeScript 集成。

最后更新:2026-03-28