Skip to content

@Watch 状态监听

@Watch 装饰器监听状态变量变化,在变化时执行自定义回调函数。


1. @Watch 基本用法

typescript
@Component
struct Index {
    @Watch('onCountChange')  // 监听 count 变化
    @State count: number = 0

    @Watch('onNameChange')  // 监听 name 变化
    @State name: string = 'Hello'

    // 回调函数
    onCountChange(oldValue: number, newValue: number): void {
        console.log(`count 变化: ${oldValue} → ${newValue}`)
        // 可以在这里执行副作用逻辑
    }

    onNameChange(oldValue: string, newValue: string): void {
        console.log(`name 变化: ${oldValue} → ${newValue}`)
    }

    build() {
        Column() {
            Text(`计数: ${this.count}`)
            Button('增加')
                .onClick(() => {
                    this.count++  // 触发 onCountChange
                })
        }
    }
}

2. @Watch 的回调函数签名

typescript
// 标准签名
function onNameChange(oldValue: T, newValue: T): void {
    // oldValue: 变化前的值
    // newValue: 变化后的值
}

回调中可以做什麼

可以做不可以做
发起网络请求修改 UI 状态(避免循环)
日志记录在 build() 中
数据转换/计算触发其他 @State 变化
发送事件通知同步阻塞操作

3. 实际应用场景

3.1 数据变化时自动请求

typescript
@Component
struct SearchPage {
    @Watch('onKeywordChange')
    @State keyword: string = ''
    @State results: SearchResult[] = []

    // 关键词变化时自动搜索
    onKeywordChange(oldValue: string, newValue: string): void {
        if (newValue.length >= 2) {
            this.search(newVal)
        }
    }

    async search(keyword: string) {
        const response = await http.get(`/api/search?q=${keyword}`)
        this.results = response.data
    }

    build() {
        Column() {
            TextInput({ placeholder: '搜索' })
                .onChange((value: string) => {
                    this.keyword = value
                })
            ForEach(this.results, (item: SearchResult) => {
                Text(item.title)
            })
        }
    }
}

3.2 权限监听

typescript
@Component
struct CameraPage {
    @Watch('onCameraPermissionChange')
    @State hasCameraPermission: boolean = false

    onCameraPermissionChange(oldValue: boolean, newValue: boolean): void {
        if (!newValue) {
            // 权限被拒绝,跳转设置页
            console.log('相机权限被拒绝')
        }
    }

    build() {
        if (this.hasCameraPermission) {
            CameraView()
        } else {
            Text('请授予相机权限')
        }
    }
}

3.3 数据同步

typescript
@Component
struct SyncPage {
    @Watch('onNetworkChange')
    @State isOnline: boolean = true
    @State pendingData: any[] = []

    onNetworkChange(oldValue: boolean, newValue: boolean): void {
        if (newValue && this.pendingData.length > 0) {
            // 网络恢复,同步待上传数据
            this.uploadPendingData()
        }
    }

    async uploadPendingData() {
        for (const data of this.pendingData) {
            await http.post('/api/sync', data)
        }
        this.pendingData = []
    }

    build() {
        Text(this.isOnline ? '在线' : '离线')
    }
}

4. @Watch 的限制

4.1 回调函数必须是同步的

typescript
// ✅ 正确:同步回调
@Watch('onChange')
@State value: string = ''

onChange(oldValue: string, newValue: string): void {
    console.log(newValue)  // 同步处理
}

// ❌ 错误:async 函数(@Watch 不支持)
@Watch('onChange')
@State value: string = ''

async onChange(oldValue: string, newValue: string): void {
    await fetchData()  // ❌ @Watch 回调不支持 async
}

4.2 避免循环触发

typescript
// ❌ 循环触发!
@Watch('onAChange')
@State a: number = 0

@Watch('onBChange')
@State b: number = 0

onAChange(oldValue: number, newValue: number): void {
    this.b = newValue + 1  // 触发 onBChange
}

onBChange(oldValue: number, newValue: number): void {
    this.a = newValue + 1  // 触发 onAChange → 死循环!
}

5. 状态管理方案总结

装饰器作用场景
@State本地状态组件内部私有状态
@Prop单向传参父→子只读数据
@Link双向绑定父↔子双向同步
@ObjectLink深度绑定嵌套对象监听
@Provide跨树提供祖父→后代数据传递
@Consume跨树消费后代获取祖父数据
@Watch变化监听状态变化时触发副作用
@Observed类标记配合 @ObjectLink 深度监听

6. 面试高频考点

Q1: @Watch 的作用?

回答:监听 @State 状态变量的变化,在变化时执行自定义回调函数。可用于自动请求、数据同步、权限监听等场景。

Q2: @Watch 回调的限制?

回答:回调必须是同步函数,不能是 async;不能在回调中修改其他 @State 避免循环触发;不能在 build() 中执行。


🐱 小猫提示:@Watch 记住 "状态变化→执行回调→做副作用(请求/同步/日志)"