harmony 鸿蒙getTarget API: Obtaining Original Objects
getTarget API: Obtaining Original Objects
To obtain the original object before adding a proxy in the state management, you can use the getTarget API.
Before reading this topic, you are advised to read \@Observed and \@ObservedV2.
NOTE
The getTarget API in UIUtils is supported since API version 12.
Overview
The state management framework adds proxies to original objects of the class, Date, Map, Set, and Array types to observe attribute changes and API invoking. Proxies will change the variable types. In scenarios such as type determination and Node-API invoking, unexpected results may be generated because the variable type is not the type of the original object.
- Import the UIUtils to use the getTarget API.
import { UIUtils } from '@kit.ArkUI';
- In state management V1, a proxy is added to the class objects decorated by @Observed and the class, Date, Map, Set, and Array decorated by @State or other state variable decorators to observe the changes of top-level attributes or changes invoked by APIs.
- In state management V2, a proxy is added to Date, Map, Set, and Array decorated by \@Trace, \@Local or other state variable decorators to observe changes invoked by APIs.
Use getTarget to obtain the original objects of these proxy objects.
Constraints
- Only the parameters of the object type can be passed by getTarget.
import { UIUtils } from '@kit.ArkUI';
let res = UIUtils.getTarget(2); // Incorrect usage. The input parameter is of the non-object type.
@Observed
class Info {
name: string = "Tom";
}
let info: Info = new Info();
let rawInfo: Info = UIUtils.getTarget (info); // Correct usage.
- Changes to the content in the original object obtained by getTarget cannot be observed nor trigger UI re-renders.
import { UIUtils } from '@kit.ArkUI';
@Observed
class Info {
name: string = "Tom";
}
@Entry
@Component
struct Index {
@State info: Info = new Info();
build() {
Column() {
Text(`info.name: ${this.info.name}`)
Button(`Change the attributes of the proxy object`)
.onClick(() => {
this.info.name = "Alice"; // Text component can be re-rendered.
})
Button(`Change the attributes of the original object`)
.onClick(() => {
let rawInfo: Info = UIUtils.getTarget(this.info);
The rawInfo.name = "Bob"; // Text component cannot be re-rendered.
})
}
}
}
Use Scenarios
Obtaining the Original Object Before Adding a Proxy in the State Management V1
State management V1 adds proxies to objects in the following scenarios:
- \@Observed decorated class instance. When this class instance is created, a proxy is added to the instance. However, objects that are not created by using the new operator are not proxied.
@Observed
class ObservedClass {
name: string = "Tom";
}
class NonObservedClass {
name: string = "Tom";
}
let observedClass: ObservedClass = new ObservedClass(); // Proxied.
let nonObservedClass: NonObservedClass = new NonObservedClass(); // Not proxied.
- Complex object decorated by the state variable decorator. When state variables decorators such as \@State or \@Prop are used to decorate Class, Map, Set, Date, and Array, proxies are added. If the object is already a proxy object, the proxy will not be created again.
@Observed
class ObservedClass {
name: string = "Tom";
}
class NonObservedClass {
name: string = "Tom";
}
let observedClass: ObservedClass = new ObservedClass(); // Proxied.
let nonObservedClass: NonObservedClass = new NonObservedClass(); // Not proxied.
@Entry
@Component
struct Index {
@State observedObject: ObservedClass = observedClass; // Proxy will not be created repeatedly for proxied data.
@State nonObservedObject: NonObservedClass = nonObservedClass; // A proxy is created.
@State numberList: number[] = [1, 2, 3]; // A proxy is created for the Array type.
@State sampleMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]); // A proxy is created for the Map type.
@State sampleSet: Set<number> = new Set([0, 1, 2, 3, 4]); // A proxy is created for the Set type.
@State sampleDate: Date = new Date(); // A proxy is created for the Date type.
build() {
Column() {
Text(`this.observedObject === observedClass: ${this.observedObject === observedClass}`) // true
Text(`this.nonObservedObject === nonObservedClass: ${this.nonObservedObject === nonObservedClass}`) // false
}
}
}
Use UIUtils.getTarget to obtain the original objects before proxies are added.
import { UIUtils } from '@kit.ArkUI';
@Observed
class ObservedClass {
name: string = "Tom";
}
class NonObservedClass {
name: string = "Tom";
}
let observedClass: ObservedClass = new ObservedClass(); // Proxied.
let nonObservedClass: NonObservedClass = new NonObservedClass(); // Not proxied.
let globalNumberList: number[] = [1, 2, 3]; // Not proxied.
let globalSampleMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]); // Not proxied.
let globalSampleSet: Set<number> = new Set([0, 1, 2, 3, 4]); // Not proxied.
let globalSampleDate:Date = new Date (); // Not proxied.
@Entry
@Component
struct Index {
@State observedObject: ObservedClass = observedClass; // Proxy will not be created repeatedly for proxied data.
@State nonObservedObject: NonObservedClass = nonObservedClass; // A proxy is created.
@State numberList: number[] = globalNumberList; // A proxy is created for the Array type.
@State sampleMap: Map<number, string> = globalSampleMap; // A proxy is created for the Map type.
@State sampleSet: Set<number> = globalSampleSet; // A proxy is created for the Set type.
@State sampleDate: Date = globalSampleDate; // A proxy is created for the Date type.
build() {
Column() {
Text(`this.observedObject === observedClass: ${this.observedObject ===
observedClass}`) // true
Text(`UIUtils.getTarget(this.nonObservedObject) === nonObservedClass: ${UIUtils.getTarget(this.nonObservedObject) ===
nonObservedClass}`) // true
Text(`UIUtils.getTarget(this.numberList) === globalNumberList: ${UIUtils.getTarget(this.numberList) ===
globalNumberList}`) // true
Text(`UIUtils.getTarget(this.sampleMap) === globalSampleMap: ${UIUtils.getTarget(this.sampleMap) ===
globalSampleMap}`) // true
Text(`UIUtils.getTarget(this.sampleSet) === globalSampleSet: ${UIUtils.getTarget(this.sampleSet) ===
globalSampleSet}`) // true
Text(`UIUtils.getTarget(this.sampleDate) === globalSampleDate: ${UIUtils.getTarget(this.sampleDate) ===
globalSampleDate}`) // true
}
}
}
Obtaining the Original Object Before Adding a Proxy in the State Management V2
A proxy is added to the Map, Set, Date, and Array decorated by \@Trace, \@Local, or other state variable decorators in state management V2. Different from state management V1, the class object instances are not proxied in state management V2.
@ObservedV2
class ObservedClass {
@Trace name: string = "Tom";
}
let globalObservedObject: ObservedClass = new ObservedClass(); // Not proxied.
let globalNumberList: number[] = [1, 2, 3]; // Not proxied.
let globalSampleMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]); // Not proxied.
let globalSampleSet: Set<number> = new Set([0, 1, 2, 3, 4]); // Not proxied.
let globalSampleDate:Date = new Date (); // Not proxied.
@Entry
@ComponentV2
struct Index {
@Local observedObject: ObservedClass = globalObservedObject; // Objects in V2 are not proxied.
@Local numberList: number[] = globalNumberList; // A proxy is created for the Array type.
@Local sampleMap: Map<number, string> = globalSampleMap; // A proxy is created for the Map type.
@Local sampleSet: Set<number> = globalSampleSet; // A proxy is created for the Set type.
@Local sampleDate: Date = globalSampleDate; // A proxy is created for the Date type.
build() {
Column() {
Text(`this.observedObject === globalObservedObject ${this.observedObject === globalObservedObject}`) // true
Text(`this.numberList === globalNumberList ${this.numberList === globalNumberList}`) // false
}
}
}
Use UIUtils.getTarget to obtain the original objects before proxies are added.
import { UIUtils } from '@kit.ArkUI';
@ObservedV2
class ObservedClass {
@Trace name: string = "Tom";
}
let globalObservedObject: ObservedClass = new ObservedClass(); // Not proxied.
let globalNumberList: number[] = [1, 2, 3]; // Not proxied.
let globalSampleMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]); // Not proxied.
let globalSampleSet: Set<number> = new Set([0, 1, 2, 3, 4]); // Not proxied.
let globalSampleDate:Date = new Date (); // Not proxied.
@Entry
@ComponentV2
struct Index {
@Local observedObject: ObservedClass = globalObservedObject; // Objects in V2 are not proxied.
@Local numberList: number[] = globalNumberList; // A proxy is created for the Array type.
@Local sampleMap: Map<number, string> = globalSampleMap; // A proxy is created for the Map type.
@Local sampleSet: Set<number> = globalSampleSet; // A proxy is created for the Set type.
@Local sampleDate: Date = globalSampleDate; // A proxy is created for the Date type.
build() {
Column() {
Text(`this.observedObject === globalObservedObject ${this.observedObject ===
globalObservedObject}`) // true
Text(`UIUtils.getTarget(this.numberList) === globalNumberList: ${UIUtils.getTarget(this.numberList) ===
globalNumberList}`) // true
Text(`UIUtils.getTarget(this.sampleMap) === globalSampleMAP: ${UIUtils.getTarget(this.sampleMap) ===
globalSampleMap}`) // true
Text(`UIUtils.getTarget(this.sampleSet) === globalSampleSet: ${UIUtils.getTarget(this.sampleSet) ===
globalSampleSet}`) // true
Text(`UIUtils.getTarget(this.sampleDate) === globalSampleDate: ${UIUtils.getTarget(this.sampleDate) ===
globalSampleDate}`) // true
}
}
}
Decorators in state management V2 generate the getter and setter methods for the decorated variables and add prefix __ob_ in the original variable names. To ensure performance, the getTarget API does not process the prefix generated by the decorators in V2. Therefore, when the \@ObservedV2 decorated class object instance is passed in through getTarget API, the returned object is still the object itself and the attribute name decorated by \@Trace still has the prefix __ob_.
Some Node-APIs fail to process object attributes as expected due to this prefix.
Example:
Affected Node-APIs are as below.
// Class decorated by @ObservedV2.
@ObservedV2
class Info {
@Trace name: string = "Tom";
@Trace age: number = 24;
}
let info: Info = new Info(); // info instance passed in through Node-APIs.
Name | Result |
---|---|
napi_get_property_names | Returns value that is __ob_name or __ob_age. |
napi_set_property | Changes values successfully using name or __ob_name. |
napi_get_property | Obtains values using name or __ob_name. |
napi_has_property | Returns true using name or __ob_name. |
napi_delete_property | Deletes an attribute successfully adding the prefix __ob_. |
napi_has_own_property | Returns true using name or __ob_name. |
napi_set_named_property | Changes values successfully using name or __ob_name. |
napi_get_named_property | Obtains values using name or __ob_name. |
napi_has_named_property | Returns true using name or __ob_name. |
你可能感兴趣的鸿蒙文章
harmony 鸿蒙\@AnimatableExtend Decorator: Definition of Animatable Attributes
harmony 鸿蒙Application State Management Overview
harmony 鸿蒙AppStorage: Storing Application-wide UI State
harmony 鸿蒙Basic Syntax Overview
harmony 鸿蒙\@Builder Decorator: Custom Builder Function
harmony 鸿蒙\@BuilderParam Decorator: Referencing the \@Builder Function
harmony 鸿蒙Creating a Custom Component
harmony 鸿蒙Mixing Use of Custom Components
harmony 鸿蒙Constraints on Access Modifiers of Custom Component Member Variables
- 所属分类: 后端技术
- 本文标签:
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦