Observer组件 #

Observer 是 mobx-react-lite 提供的一个组件,它提供了一种更细粒度的响应式更新方式。与 observer 高阶组件不同,Observer 只追踪其 children 函数中使用的状态。

基本用法 #

简单示例 #

javascript
import { Observer } from 'mobx-react-lite';

const Counter = () => {
  return (
    <div>
      <Observer>
        {() => <span>{counterStore.count}</span>}
      </Observer>
      <button onClick={() => counterStore.increment()}>+1</button>
    </div>
  );
};

与observer的区别 #

javascript
// observer:整个组件被追踪
const Counter1 = observer(() => {
  return (
    <div>
      <span>{counterStore.count}</span>
      <span>{otherStore.value}</span>
    </div>
  );
});
// count 或 value 变化都会触发整个组件重新渲染

// Observer:只追踪 children 内的状态
const Counter2 = () => {
  return (
    <div>
      <Observer>
        {() => <span>{counterStore.count}</span>}
      </Observer>
      <span>{otherStore.value}</span>
    </div>
  );
};
// 只有 count 变化才会重新渲染 Observer 内的内容
// value 变化会触发整个组件重新渲染

使用场景 #

1. 局部状态追踪 #

javascript
import { Observer } from 'mobx-react-lite';

const UserProfile = ({ user }) => {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>

      {/* 只有 status 变化时才更新这部分 */}
      <Observer>
        {() => (
          <span className={`status ${user.status}`}>
            {user.status}
          </span>
        )}
      </Observer>
    </div>
  );
};

2. 列表项优化 #

javascript
const TodoList = () => {
  return (
    <ul>
      {todoStore.todos.map(todo => (
        <Observer key={todo.id}>
          {() => (
            <li style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
              {todo.title}
              <button onClick={() => todo.toggle()}>Toggle</button>
            </li>
          )}
        </Observer>
      ))}
    </ul>
  );
};

3. 条件渲染优化 #

javascript
const ConditionalComponent = () => {
  return (
    <div>
      <h1>Dashboard</h1>

      {/* 只有 isLoggedIn 变化时才更新 */}
      <Observer>
        {() => (
          authStore.isLoggedIn ? <UserPanel /> : <LoginButton />
        )}
      </Observer>
    </div>
  );
};

完整示例 #

实时数据展示 #

javascript
import { makeAutoObservable } from 'mobx';
import { Observer } from 'mobx-react-lite';

class StockStore {
  stocks = new Map();
  selectedSymbol = null;

  constructor() {
    makeAutoObservable(this);
  }

  updatePrice(symbol, price) {
    this.stocks.set(symbol, price);
  }

  selectStock(symbol) {
    this.selectedSymbol = symbol;
  }

  get selectedPrice() {
    return this.stocks.get(this.selectedSymbol);
  }
}

const stockStore = new StockStore();

const StockPrice = ({ symbol }) => {
  return (
    <Observer>
      {() => {
        const price = stockStore.stocks.get(symbol);
        return (
          <div className="stock-price">
            {symbol}: ${price?.toFixed(2) || 'N/A'}
          </div>
        );
      }}
    </Observer>
  );
};

const StockList = () => {
  return (
    <div>
      <h2>Stock Prices</h2>
      <div className="stock-grid">
        {['AAPL', 'GOOGL', 'MSFT'].map(symbol => (
          <StockPrice key={symbol} symbol={symbol} />
        ))}
      </div>
    </div>
  );
};

表单字段 #

javascript
import { makeAutoObservable } from 'mobx';
import { Observer } from 'mobx-react-lite';

class FormStore {
  values = {};
  errors = {};

  constructor() {
    makeAutoObservable(this);
  }

  setValue(field, value) {
    this.values[field] = value;
  }

  setError(field, error) {
    this.errors[field] = error;
  }

  getError(field) {
    return this.errors[field];
  }
}

const formStore = new FormStore();

const FormField = ({ name, label, type = 'text' }) => {
  return (
    <div className="form-field">
      <label>{label}</label>
      <Observer>
        {() => (
          <input
            type={type}
            value={formStore.values[name] || ''}
            onChange={(e) => formStore.setValue(name, e.target.value)}
          />
        )}
      </Observer>
      <Observer>
        {() => {
          const error = formStore.getError(name);
          return error ? <span className="error">{error}</span> : null;
        }}
      </Observer>
    </div>
  );
};

const Form = () => {
  return (
    <form>
      <FormField name="username" label="Username" />
      <FormField name="email" label="Email" type="email" />
      <FormField name="password" label="Password" type="password" />
    </form>
  );
};

进度条 #

javascript
import { makeAutoObservable } from 'mobx';
import { Observer } from 'mobx-react-lite';

class ProgressStore {
  progress = 0;
  status = 'idle';

  constructor() {
    makeAutoObservable(this);
  }

  start() {
    this.status = 'loading';
    this.progress = 0;
  }

  update(progress) {
    this.progress = progress;
  }

  complete() {
    this.status = 'complete';
    this.progress = 100;
  }
}

const progressStore = new ProgressStore();

const ProgressBar = () => {
  return (
    <div className="progress-container">
      <Observer>
        {() => (
          <div
            className="progress-bar"
            style={{ width: `${progressStore.progress}%` }}
          />
        )}
      </Observer>
      <Observer>
        {() => (
          <span className="progress-text">
            {progressStore.progress}%
          </span>
        )}
      </Observer>
    </div>
  );
};

Observer vs observer #

特性 Observer observer
使用方式 组件 高阶函数
追踪范围 children 内 整个组件
灵活性
性能 更细粒度 整体更新
适用场景 局部更新 整体响应

选择建议 #

javascript
// 使用 observer:整个组件都需要响应状态
const TodoItem = observer(({ todo }) => (
  <li>
    <span>{todo.title}</span>
    <span>{todo.status}</span>
  </li>
));

// 使用 Observer:只有部分需要响应
const TodoItem = ({ todo }) => (
  <li>
    <span>{todo.title}</span>
    <Observer>
      {() => <span>{todo.status}</span>}
    </Observer>
  </li>
);

性能优化技巧 #

1. 避免过度使用 #

javascript
// 不好:过度使用 Observer
const Component = () => (
  <div>
    <Observer>{() => <span>{store.a}</span>}</Observer>
    <Observer>{() => <span>{store.b}</span>}</Observer>
    <Observer>{() => <span>{store.c}</span>}</Observer>
  </div>
);

// 好:合并使用
const Component = () => (
  <Observer>
    {() => (
      <div>
        <span>{store.a}</span>
        <span>{store.b}</span>
        <span>{store.c}</span>
      </div>
    )}
  </Observer>
);

2. 配合React.memo #

javascript
const StaticPart = React.memo(({ data }) => (
  <div>{data}</div>
));

const DynamicComponent = () => (
  <div>
    <StaticPart data={staticData} />
    <Observer>
      {() => <span>{store.dynamicValue}</span>}
    </Observer>
  </div>
);

3. 列表优化 #

javascript
// 使用 Observer 包裹列表项
const TodoList = () => (
  <ul>
    {store.todos.map(todo => (
      <Observer key={todo.id}>
        {() => (
          <li style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
            {todo.title}
          </li>
        )}
      </Observer>
    ))}
  </ul>
);

注意事项 #

1. key的位置 #

javascript
// 错误:key 在 Observer 上
<Observer key={item.id}>
  {() => <div>{item.name}</div>}
</Observer>

// 正确:key 在内部元素上
<Observer>
  {() => <div key={item.id}>{item.name}</div>}
</Observer>

2. 不要在Observer外访问状态 #

javascript
// 错误:在 Observer 外访问状态
const value = store.value;
<Observer>
  {() => <span>{value}</span>}
</Observer>

// 正确:在 Observer 内访问状态
<Observer>
  {() => <span>{store.value}</span>}
</Observer>

总结 #

Observer 组件的核心要点:

  • 细粒度追踪:只追踪 children 内的状态
  • 局部更新:减少不必要的渲染
  • 灵活使用:适合局部响应式场景

使用建议:

  • 整体响应式:使用 observer
  • 局部响应式:使用 Observer
  • 列表项优化:使用 Observer 包裹
  • 避免过度拆分

继续学习 useLocalObservable,了解组件内状态管理。

最后更新:2026-03-28