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