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

如何在 React 中使用 MobX 的 observer?

2月19日 17:58

在 MobX 中,observer 是一个高阶组件(HOC),用于将 React 组件转换为响应式组件。当组件使用的数据发生变化时,组件会自动重新渲染。

observer 的基本用法

1. 类组件中使用 observer

javascript
import React from 'react'; import { observer } from 'mobx-react'; import { observable } from 'mobx'; class Store { @observable count = 0; } const store = new Store(); @observer class Counter extends React.Component { render() { return ( <div> <p>Count: {store.count}</p> <button onClick={() => store.count++}>Increment</button> </div> ); } }

2. 函数组件中使用 observer

javascript
import React from 'react'; import { observer } from 'mobx-react-lite'; import { observable } from 'mobx'; class Store { @observable count = 0; } const store = new Store(); const Counter = observer(() => { return ( <div> <p>Count: {store.count}</p> <button onClick={() => store.count++}>Increment</button> </div> ); });

observer 的工作原理

1. 组件挂载时

  • MobX 创建一个 reaction 来追踪组件 render 函数中访问的所有 observable
  • 建立组件与 observable 之间的依赖关系

2. 状态变化时

  • 当 observable 被修改时,MobX 检测到依赖变化
  • 将组件标记为需要重新渲染
  • 在下一个事件循环中,触发组件的重新渲染

3. 组件卸载时

  • 自动清理 reaction 和依赖关系
  • 避免内存泄漏

observer 的优化特性

1. 细粒度更新

observer 只会重新渲染真正需要更新的组件:

javascript
@observer class Parent extends React.Component { render() { return ( <div> <ChildA /> <ChildB /> </div> ); } } @observer class ChildA extends React.Component { render() { // 只依赖 store.count return <div>Count: {store.count}</div>; } } @observer class ChildB extends React.Component { render() { // 只依赖 store.name return <div>Name: {store.name}</div>; } }

store.count 变化时,只有 ChildA 会重新渲染,ChildB 不会。

2. shouldComponentUpdate 优化

observer 会自动实现 shouldComponentUpdate,避免不必要的渲染:

  • 只有当组件依赖的 observable 真正变化时才重新渲染
  • 即使父组件重新渲染,子组件也可能不会重新渲染

3. 批量更新

多个状态变化会被批量处理,只触发一次重新渲染:

javascript
runInAction(() => { store.count++; store.name = 'New Name'; });

observer 的最佳实践

1. 只在需要的地方使用 observer

不是所有组件都需要 observer,只在需要响应状态变化的组件上使用:

javascript
// 不需要 observer const Header = () => <h1>My App</h1>; // 需要 observer const Counter = observer(() => { return <div>Count: {store.count}</div>; });

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

在 render 中创建新对象会导致不必要的重新渲染:

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

3. 使用 computed 优化计算

在组件外部使用 computed 来优化计算逻辑:

javascript
// 不好的做法 const BadComponent = observer(() => { const fullName = `${store.firstName} ${store.lastName}`; return <div>{fullName}</div>; }); // 好的做法 class Store { @observable firstName = 'John'; @observable lastName = 'Doe'; @computed get fullName() { return `${this.firstName} ${this.lastName}`; } } const GoodComponent = observer(() => { return <div>{store.fullName}</div>; });

4. 使用 React.memo 配合 observer

对于纯展示组件,可以结合 React.memo 使用:

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

常见问题

1. 组件不更新

确保:

  • 组件被 observer 包装
  • 访问的是 observable 而不是普通对象
  • 状态修改在 action 中进行

2. 过度渲染

如果组件过度渲染,检查:

  • 是否在 render 中创建了新对象
  • 是否使用了 computed 来优化计算
  • 是否可以拆分组件以减少依赖

3. 内存泄漏

确保:

  • 组件卸载时 observer 会自动清理
  • 手动创建的 reaction 需要手动清理

总结

observer 是 MobX 与 React 集成的核心,它通过细粒度的依赖追踪实现了高效的响应式更新。正确使用 observer 和遵循最佳实践,可以构建高性能的 React 应用。

标签:ReactMobx