When条件执行 #
when 是 MobX 提供的一个条件响应函数。它会观察条件,当条件变为 true 时执行副作用,然后自动清除。when 非常适合处理"等待某个状态"的场景。
基本用法 #
简单示例 #
javascript
import { makeAutoObservable, when } from 'mobx';
class Store {
isLoggedIn = false;
user = null;
constructor() {
makeAutoObservable(this);
}
}
const store = new Store();
// 当 isLoggedIn 变为 true 时执行
when(
() => store.isLoggedIn,
() => {
console.log('User is now logged in!');
loadUserData();
}
);
// 触发条件
store.isLoggedIn = true; // 输出: User is now logged in!
// when 自动清除,之后的变化不再触发
store.isLoggedIn = false;
store.isLoggedIn = true; // 不会再次触发
工作原理 #
text
┌─────────────────────────────────────────────────────────────┐
│ when 工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ when( │
│ () => condition, // 1. 条件函数 │
│ () => { } // 2. 副作用函数 │
│ ) │
│ │
│ 执行流程: │
│ 1. 检查条件是否为 true │
│ ├── true:立即执行副作用,然后清除 │
│ └── false:等待条件变化 │
│ 2. 条件变为 true 时,执行副作用 │
│ 3. 自动清除,不再监听 │
│ │
└─────────────────────────────────────────────────────────────┘
返回Promise #
when 可以不传副作用函数,返回一个 Promise:
javascript
import { when } from 'mobx';
// 返回 Promise
await when(() => store.isLoggedIn);
console.log('User is logged in!');
// 在 async 函数中使用
async function waitForLogin() {
await when(() => store.isLoggedIn);
console.log('User logged in, loading data...');
await loadUserData();
}
清除when #
when 返回一个清除函数:
javascript
const dispose = when(
() => store.condition,
() => {
console.log('Condition met!');
}
);
// 手动清除
dispose();
使用场景 #
等待数据加载完成 #
javascript
import { makeAutoObservable, when } from 'mobx';
class DataStore {
data = null;
loading = false;
constructor() {
makeAutoObservable(this);
}
async fetchData() {
this.loading = true;
const response = await fetch('/api/data');
this.data = await response.json();
this.loading = false;
}
}
const store = new DataStore();
store.fetchData();
// 等待数据加载完成
when(
() => store.data !== null,
() => {
console.log('Data loaded:', store.data);
processData(store.data);
}
);
等待用户登录 #
javascript
import { makeAutoObservable, when } from 'mobx';
class AuthStore {
isLoggedIn = false;
user = null;
constructor() {
makeAutoObservable(this);
}
async login(credentials) {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(credentials)
});
const user = await response.json();
this.user = user;
this.isLoggedIn = true;
}
}
const authStore = new AuthStore();
// 等待登录后执行操作
async function performActionAfterLogin() {
await when(() => authStore.isLoggedIn);
console.log('User logged in:', authStore.user.name);
await loadPrivateData();
}
等待条件满足 #
javascript
import { makeAutoObservable, when } from 'mobx';
class GameStore {
score = 0;
level = 1;
gameOver = false;
constructor() {
makeAutoObservable(this);
// 等待达到特定分数
when(
() => this.score >= 1000,
() => {
console.log('Achievement unlocked: Score 1000!');
this.unlockAchievement('score_1000');
}
);
// 等待游戏结束
when(
() => this.gameOver,
() => {
this.showGameOverScreen();
}
);
}
addScore(points) {
this.score += points;
}
endGame() {
this.gameOver = true;
}
unlockAchievement(id) { }
showGameOverScreen() { }
}
完整示例 #
模态框等待 #
javascript
import { makeAutoObservable, when } from 'mobx';
class ModalStore {
isOpen = false;
result = null;
constructor() {
makeAutoObservable(this);
}
open() {
this.isOpen = true;
this.result = null;
}
close(result = null) {
this.isOpen = false;
this.result = result;
}
}
const confirmStore = new ModalStore();
// 显示确认对话框并等待结果
async function showConfirm(message) {
confirmStore.open();
// 等待对话框关闭
await when(() => !confirmStore.isOpen);
return confirmStore.result;
}
// 使用
async function deleteItem() {
const confirmed = await showConfirm('Are you sure?');
if (confirmed) {
// 执行删除
}
}
表单验证等待 #
javascript
import { makeAutoObservable, when } from 'mobx';
class FormStore {
values = {};
errors = {};
validating = false;
constructor() {
makeAutoObservable(this);
}
get isValid() {
return Object.keys(this.errors).length === 0;
}
async validate() {
this.validating = true;
// 模拟异步验证
await new Promise(resolve => setTimeout(resolve, 500));
// 验证逻辑
this.errors = {};
if (!this.values.email) {
this.errors.email = 'Email is required';
}
this.validating = false;
}
async submit() {
await this.validate();
// 等待验证完成且有效
await when(() => !this.validating);
if (this.isValid) {
await this.sendForm();
}
}
async sendForm() {
// 发送表单
}
}
文件上传等待 #
javascript
import { makeAutoObservable, when, runInAction } from 'mobx';
class UploadStore {
files = [];
uploading = false;
progress = 0;
constructor() {
makeAutoObservable(this);
}
async uploadFiles(files) {
this.uploading = true;
this.progress = 0;
for (let i = 0; i < files.length; i++) {
await this.uploadFile(files[i]);
runInAction(() => {
this.progress = ((i + 1) / files.length) * 100;
});
}
runInAction(() => {
this.uploading = false;
});
}
async uploadFile(file) {
// 上传单个文件
}
}
const uploadStore = new UploadStore();
// 等待上传完成
async function waitForUpload() {
uploadStore.uploadFiles(selectedFiles);
await when(() => !uploadStore.uploading);
console.log('All files uploaded!');
}
WebSocket连接等待 #
javascript
import { makeAutoObservable, when, runInAction } from 'mobx';
class WebSocketStore {
connected = false;
socket = null;
constructor() {
makeAutoObservable(this);
this.connect();
}
connect() {
this.socket = new WebSocket('ws://localhost:8080');
this.socket.onopen = () => {
runInAction(() => {
this.connected = true;
});
};
this.socket.onclose = () => {
runInAction(() => {
this.connected = false;
});
};
}
async send(message) {
// 等待连接建立
await when(() => this.connected);
this.socket.send(JSON.stringify(message));
}
disconnect() {
if (this.socket) {
this.socket.close();
}
}
}
const wsStore = new WebSocketStore();
// 等待连接后发送消息
async function sendMessage(data) {
await wsStore.send({ type: 'message', data });
}
高级用法 #
超时处理 #
javascript
async function waitForConditionWithTimeout(timeout = 5000) {
const result = await Promise.race([
when(() => store.condition),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
return result;
}
// 使用
try {
await waitForConditionWithTimeout();
console.log('Condition met!');
} catch (error) {
console.log('Timeout waiting for condition');
}
条件组合 #
javascript
// 等待多个条件
when(
() => store.isLoggedIn && store.dataLoaded,
() => {
console.log('Ready to show dashboard');
}
);
// 等待任一条件
when(
() => store.success || store.error,
() => {
if (store.success) {
showSuccess();
} else {
showError(store.error);
}
}
);
嵌套when #
javascript
when(
() => store.step === 1,
() => {
console.log('Step 1 complete');
when(
() => store.step === 2,
() => {
console.log('Step 2 complete');
}
);
}
);
when vs reaction vs autorun #
| 特性 | when | reaction | autorun |
|---|---|---|---|
| 执行次数 | 一次 | 多次 | 多次 |
| 条件触发 | 是 | 是 | 否 |
| 立即执行 | 条件为true时 | 否(默认) | 是 |
| 自动清除 | 是 | 否 | 否 |
| 返回Promise | 支持 | 否 | 否 |
选择建议:
- 等待某个条件满足:使用
when - 条件满足后只执行一次:使用
when - 条件满足后多次执行:使用
reaction - 立即执行并持续响应:使用
autorun
总结 #
when 的核心要点:
- 一次性执行:条件满足后自动清除
- 条件驱动:等待条件变为 true
- Promise支持:可以返回 Promise
- 适合等待场景:非常适合"等待某事发生"的场景
使用场景:
- 等待数据加载完成
- 等待用户登录
- 等待条件满足
- 等待异步操作完成
继续学习 Observer观察者,了解 MobX 与 React 的集成。
最后更新:2026-03-28