为什么你写的鸿蒙 State 变量刷新为什么时好时坏

背景

有一次开发碰到了这样一个问题:下面的 Bad case 写法在鸿蒙上不会触发组件重新 build,进而导致页面状态没有刷新。

Bad case 写法

class BadState {
  tick: number = 0

  constructor() {
    this.startTimer()
  }

  private startTimer() {
    setInterval(() => {
      this.tick++
    }, 1000)
  }
}

@Component
struct Bad {
  @State state: BadState = new BadState()

  build() {
    Stack() {
      Text(`Tick: ${this.state.tick}`)
    }
  }
}

Good case 写法

@Component
struct Good {
  @State state: GoodState = new GoodState()

  aboutToAppear(): void {
    this.state.startTimer()
  }

  build() {
    Stack() {
      Text(`Tick: ${this.state.tick}`)
    }
  }
}

原因分析

Good case 逻辑:this 对象是被代理过的对象,具有监听与通知的功能。

pAboZE6.png

Bad case 逻辑:this 对象为原始对象,无监听与通知的功能。

pAboeUK.png

而上述两种逻辑差异点主要是 startTimer 的 caller 不同:Good case 中 startTimer 的 caller 是 this.state 对象,这是一个被代理过的对象;Bad 中 startTimer 的 caller 是 this 对象,即 BadState 实例本身,这是一个没有被代理过的对象。 所以根据上述分析得出结论: Bad case 中箭头函数对应的 this 指针所指的对象为 startTimer 方法的 caller, 它是一个没有被代理过的对象,对该对象的任何属性的修改都不会被 View 层感知。