HarmonyOS鸿蒙Next中如何让从Http请求返回的JSON数据转换为@ObservedV2、@Trace装饰的类的对象具有触发UI刷新的能力
HarmonyOS鸿蒙Next中如何让从Http请求返回的JSON数据转换为@ObservedV2、@Trace装饰的类的对象具有触发UI刷新的能力
@ObservedV2、@Trace装饰器使用限制
- @ObservedV2的类实例目前不支持使用JSON.stringify进行序列化。
- 使用@ObservedV2与@Trace装饰器的类,需通过new操作符实例化后,才具备被观测变化的能力。
class-transformer和reflect-metadata
可以使用class-transformer把返回的json数据转换为@ObservedV2装饰可观测的类的对象
安装
ohpm install class-transformer@0.5.1
ohpm install reflect-metadata@0.2.1
如果@ObservedV2装饰的类没有嵌套可以不需要reflect-metadata,如果有嵌套并且还要具备观测它的属性的话则需要reflect-metadata(简单讲就是如果使用了class-transformer的@Type装饰则需要import ‘reflect-metadata’)
数据源
这里采用GitHub REST API的搜索仓库的api来作为数据源:
https://api.github.com/search/repositories?q=node.js+language:javascript&sort=stars
使用@ObservedV2、@Trace装饰器和class-transformer的@Type
import 'reflect-metadata'//由于用到了class-transformer的[@Type](/user/Type)装饰,所以需要引入reflect-metadata
import {Type as TypeCT} from 'class-transformer';//防止class-transformer的[@Type](/user/Type)和状态管理V2的[@Type](/user/Type)冲突,这里换个名字
[@ObservedV2](/user/ObservedV2)
class Repositories{
@TypeCT(() => RepositoryItem)//防止class-transformer的[@Type](/user/Type)和状态管理V2的[@Type](/user/Type)冲突,这里换个名字
[@Trace](/user/Trace)
items: RepositoryItem[] = []
}
[@ObservedV2](/user/ObservedV2)
class RepositoryItem {
description: string;
full_name: string
id: number
name: string
[@Trace](/user/Trace)
stargazers_count :number
constructor(description: string, full_name: string, id: number, name: string, stargazers_count: number) {
this.description = description;
this.full_name = full_name;
this.id = id;
this.name = name;
this.stargazers_count = stargazers_count;
}
}
作为栗子用,所以只取了小部分字段
axios请求http获取repositories,点击item更新star
@Entry
@ComponentV2
struct RepositoriesPage {
@Local repositories :Repositories = new Repositories()
aboutToAppear(): void {
//http请求
axios.get<Repositories,AxiosResponse<Repositories>>('/search/repositories?q=node.js+language:javascript&sort=stars',{baseURL:'https://api.github.com'})
.then((response:AxiosResponse<Repositories>) => {
this.repositories = response.data
})
.catch((e:BusinessError)=>{
console.error('getRepositories error:'+JSON.stringify(e))
})
}
build() {
List({space:5}){
Repeat(this.repositories.items)
.each((riItem)=>{
ListItem(){
Row(){
Text(riItem.item.name)
Text(`star:${riItem.item.stargazers_count}`)
}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding(15)
.backgroundColor($r('sys.color.background_secondary'))
}.onClick(()=>{
//修改仓库的star个数
riItem.item.stargazers_count++
})
})
.key((item) => item.id.toString())
}.width('100%').height('100%')
.padding(15)
}
}
结果发现点击item之后UI并没有更新 这是由于使用@ObservedV2与@Trace装饰器的类,需通过new操作符实例化后,才具备被观测变化的能力。
接下来用class-transfromer转换一下,修改一下:
//http请求
axios.get<ESObject,AxiosResponse<ESObject>>('/search/repositories?q=node.js+language:javascript&sort=stars',{baseURL:'https://api.github.com'})
.then((response:AxiosResponse<ESObject>) => {
this.repositories = plainToInstance(Repositories,response.data)
})
.catch((e:BusinessError)=>{
console.error('getRepositories error:'+JSON.stringify(e))
})
点击item可以刷新UI了
rcp请求http数据并转换为@ObservedV2装饰的类的对象
import { rcp } from '@kit.RemoteCommunicationKit';
import { BusinessError } from '@kit.BasicServicesKit';
import {plainToInstance } from "class-transformer";
let session: rcp.Session = rcp.createSession()
async function getRepositories(search:string):Promise<Repositories>{
let response = await session.get(`https://api.github.com/search/repositories?q=${search}&sort=stars`)
if(response.toJSON()){
//通过class-transformer将普通对象转换为类实例
return plainToInstance(Repositories, response.toJSON())
//return response.toJSON() as Repositories //如果是这种方式且Repositories是[@ObservedV2](/user/ObservedV2)装饰的类,它将不具备被观测变化的能力
}else {
return Promise.reject({code:-1,message:"response is undefined"} as BusinessError<string>);
}
}
如果是泛型类怎么办,可以让@ObservedV2、@Trace装饰的对象具备被观测变化的能力吗?
修改Repositories改为泛型
[@ObservedV2](/user/ObservedV2)
class Repositories<T>{
[@Trace](/user/Trace)
items: T[] = []
}
页面代码:
@Entry
@ComponentV2
struct RepositoriesPage {
@Local repositories :Repositories<RepositoryItem> = new Repositories()
aboutToAppear(): void {
//http请求
axios.get<ESObject,AxiosResponse<ESObject>>('/search/repositories?q=node.js+language:javascript&sort=stars',{baseURL:'https://api.github.com'})
.then((response:AxiosResponse<ESObject>) => {
const targetMap:TargetMap = {
target:Repositories,
properties: {
'items':RepositoryItem
},
}
this.repositories = plainToInstance(Repositories,response.data,{targetMaps:[targetMap]}) as Repositories<RepositoryItem>
})
.catch((e:BusinessError)=>{
console.error('getRepositories error:'+JSON.stringify(e))
})
}
build() {
List({space:5}){
Repeat(this.repositories.items)
.each((riItem)=>{
ListItem(){
Row(){
Text(riItem.item.name)
Text(`star:${riItem.item.stargazers_count}`)
}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding(15)
.backgroundColor($r('sys.color.background_secondary'))
}.onClick(()=>{
//修改仓库的star个数
riItem.item.stargazers_count++
})
})
.key((item) => item.id.toString())
}.width('100%').height('100%')
.padding(15)
}
}
搞定,点击item可以跟新UI:
更多关于HarmonyOS鸿蒙Next中如何让从Http请求返回的JSON数据转换为@ObservedV2、@Trace装饰的类的对象具有触发UI刷新的能力的实战教程也可以访问 https://www.itying.com/category-93-b0.html
nice 学习了
更多关于HarmonyOS鸿蒙Next中如何让从Http请求返回的JSON数据转换为@ObservedV2、@Trace装饰的类的对象具有触发UI刷新的能力的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,要让HTTP返回的JSON数据转换为@ObservedV2和@Trace装饰的类对象并触发UI刷新:
- 使用@ObservedV2装饰数据类
- 在JSON解析后,确保将数据赋值给@ObservedV2类的@Trace装饰属性
- 属性变更会自动触发UI刷新
示例代码:
[@ObservedV2](/user/ObservedV2)
class UserData {
[@Trace](/user/Trace) name: string = '';
}
// 解析JSON后
let user = new UserData();
user.name = jsonData.name; // 赋值会触发UI刷新,