DEV Community

HarmonyOS
HarmonyOS

Posted on

Why does @Observed stop working after assigning JSON data from a server

Read the original article:Why does @Observed stop working after assigning JSON data from a server

Question

Why does @Observed stop working after assigning server-fetched data to a variable in HarmonyOS?

Short Answer

When JSON data is received from the server, it's plain and lacks class metadata. Directly assigning it to an @Observed-decorated variable breaks reactivity. To fix this, convert the plain object into an actual class instance using class-transformer's plainToClass along with reflect-metadata. Here you can find the related code below;

myList

[{
  "id": 100,
  "c": 2,
  "url": "https://img2.baidu.com/it/u=3271634463,3958449710&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083"
}]
Enter fullscreen mode Exit fullscreen mode

view.ets

import myList from './arr.json'
import { Type, plainToClass } from 'class-transformer'
import "reflect-metadata"

let NextID: number = 1;

@Observed
class ClassA {
  public id: number;
  public c: number;
  public url?: string;

  constructor(c: number,url?:string) {
    this.id = NextID++;
    this.c = c;
    this.url = url
  }
}

@Component
struct ViewA {
  @ObjectLink a: ClassA;
  label: string = 'ViewA1';
  @State obj: ClassA = new ClassA(0)

    aboutToAppear(): void {
    this.obj = JSON.parse(JSON.stringify(this.a))
  }

  build() {
    Column() {
      Button(`ViewA [${this.label}] this.a.c = ${this.a ? this.a.c : "undefined"}`)
        .width(320)
        .margin(10)
        .onClick(() => {
          this.a.c += 1;
        })
      Image(this.a.url? this.a.url: '')
        .width(50)
        .height(50)
      Button(`itemchangeUrl`)
        .width(320)
        .margin(10)
        .onClick(() => {
          this.a.url='https://img2.baidu.com/it/u=2352701707,3390340869&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083';
          this.obj.url ='https://img2.baidu.com/it/u=2352701707,3390340869&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083';
          console.info('itemchangeurl')
        })
      Image(this.obj.url? this.a.url: '')
        .width(50)
        .height(50)
    }
  }
}
@Entry
@Component
struct ViewB {
  @State arrA: ClassA[] = [new ClassA(0,'https://img0.baidu.com/it/u=4133879726,3955771682&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083'), new ClassA(0)];
  @State url: string = 'https://img0.baidu.com/it/u=4133879726,3955771682&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083'
  @State picFlag: boolean = true
  @State arrFlag: boolean = true
  @State list: ClassA[] = []
  aboutToAppear(): void {
    this.list = this.arrA
  }
  build() {
    Column() {
      ForEach(this.list,
        (item: ClassA) => {
          ViewA({ label: `#${item.id}`, a: item })
        },
        (item: ClassA): string => item.id.toString() + item.url
      )
      Button('changeUrl')
        .onClick(() => {
          if(this.picFlag){
            this.list[0].url = 'https://img0.baidu.com/it/u=194882366,1163824946&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=667'
            this.url = 'https://img0.baidu.com/it/u=194882366,1163824946&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=667'
          }else {
            this.list[0].url = 'https://img2.baidu.com/it/u=2352701707,3390340869&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083'
            this.url = 'https://img2.baidu.com/it/u=2352701707,3390340869&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=1083'
          }
          this.picFlag = !this.picFlag
          console.info('changeSuccess',this.arrA[0].url)
        })

      Button('change List')
        .onClick(() => {
          if(this.arrFlag){
            this.list = []
            myList.forEach((v) =>{
              let tmp = plainToClass(ClassA, v)
              this.list.push(tmp)
            })
          }else {
            this.list = this.arrA
          }
          this.arrFlag = !this.arrFlag
        })
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Applicable Scenarios

This applies when you're loading lists or objects from a server (e.g., via fetch or from a .json file) and binding them to UI using @Observed, @State, or @ObjectLink. Without proper type restoration, property updates won't trigger UI updates.

Written by Emincan Ozcan

Top comments (0)