[Daily HarmonyOS Next Knowledge] Nested Components, Decorator Errors, Iterative List Refresh, Unit Conversion, Tabs Component Lifecycle
1. Issues with Nested Components in HarmonyOS ArkUI
- How to wrap a component?
- How to wrap the
build()
function of a@Component
-decorated component to implement generic loading and error displays?
Reference demo:
import { CommComponent } from './CommComponent'
import { ComponentStatus } from './CommonEnums'
@Component
export struct Index2 {
@State componentStatus: ComponentStatus = ComponentStatus.SUCCESS;
build() {
Column() {
// Pass builder content from the caller
CommComponent({ componentStatus: this.componentStatus, builder: this.successBuild })
}.height('50%').width('100%')
}
@Builder
successBuild() {
Text('成功的展示')
.fontSize(30)
.width(100)
.height(100)
.borderWidth(2)
}
}
// CommComponent's builder method (simplified)
build() {
this.builder()
}
2. Error with @Concurrent Decorator in HarmonyOS
The @Concurrent
decorator always reports an error:
"Decorator function return type is ‘void | TypedPropertyDescriptor’ but is expected to be ‘void’ or ‘any’. Type ‘TypedPropertyDescriptor’ is not assignable to type ‘void’."
Reference code:
import taskpool from '@ohos.taskpool';
@Concurrent
function testPromise(args1: number, args2: number): Promise<number> {
return new Promise<number>((testFuncA, testFuncB) => {
testFuncA(args1 + args2);
});
}
export class FCDemoTest {
public static instance: FCDemoTest = new FCDemoTest();
private constructor() {}
checkInfo() {
let task1: taskpool.Task = new taskpool.Task(testPromise, 1, 2);
taskpool.execute(task1).then((d: object) => {
console.info("task1 res is: " + d)
}).catch((e: object) => {
console.info("task1 catch e: " + e)
})
}
}
3. Refresh Issues with ForEach Lists in HarmonyOS
The publish time in a list does not update after refreshing because the data source remains identical. However, the display time is calculated as a difference between the current time and the publish time (e.g., "just now", "2 minutes ago"). Since ForEach
only checks if the data source changes, the display does not update.
Solutions:
- Add the time difference to the data source, update it during refresh, and use it as the key in
keyGenerator
. - Use a custom key generator with a dynamic value (e.g., timestamp) to force updates.
- Toggle between two identical lists to trigger re-rendering.
Example code:
@Entry
@Component
struct Index {
@State one: boolean = true;
@State two: boolean = true;
build() {
Row() {
Column() {
Row() {
Text('A')
.layoutWeight(1)
if (this.two) {
Toggle({ type: ToggleType.Switch, isOn: this.one })
.enabled(!this.two)
.onChange((isOn) => {
this.one = isOn;
})
} else {
Toggle({ type: ToggleType.Switch, isOn: this.one })
.enabled(!this.two)
.onChange((isOn) => {
this.one = isOn;
})
}
}
Row() {
Text('B')
.layoutWeight(1)
Toggle({ type: ToggleType.Switch, isOn: this.two })
.onChange((isOn) => {
this.two = isOn;
})
}
.margin({ top: "25vp" })
}
.width('100%')
.margin({ left: '24vp', right: '24vp' })
.layoutWeight(1)
}
.height('100%')
}
}
4. Unit Conversion for RenderNode in HarmonyOS
How to convert between units (e.g., vp and px) to align drawRect
dimensions with the frame?
Unit conversion reference:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-pixel-units-V5
ArkUI provides 4 pixel units, with vp as the base unit:
Unit | Description |
---|---|
px | Physical screen pixels |
vp | Screen density-dependent pixels (default unit if unspecified). Note: The vp-to-px ratio depends on screen density. |
fp | Font pixels (scale with system font size) |
lpx | Logical viewport pixels (ratio of actual to logical screen width, default designWidth=720) |
Conversion APIs:
| Method | Description |
| :-- | :-- |
| vp2px(value: number): number
| Convert vp to px |
| px2vp(value: number): number
| Convert px to vp |
| fp2px(value: number): number
| Convert fp to px |
| px2fp(value: number): number
| Convert px to fp |
| lpx2px(value: number): number
| Convert lpx to px |
| px2lpx(value: number): number
| Convert px to lpx |
5. How to Ensure a Tab Page Runs Code Every Time it Appears in HarmonyOS? (onPageShow Not Triggered)
The onPageShow
lifecycle method does not trigger when switching tabs. Instead, use the component-level aboutToAppear()
method.
Recommended approach:
- Use
onTabBarClick(event: (index: number) => void)
in the parent component to track the active tab index. - Pass the active index to child components via
@State
and@Props
. - Use
@Watch
in child components to detect index changes and callshowPage()
.
Example implementation:
// Parent component
Tabs() {
TabContent() {
ChildComponent({ activeTabIndex: $currentTabIndex })
}
.onTabBarClick((index) => {
this.currentTabIndex = index;
})
}
// Child component
@Component
struct ChildComponent {
@Props activeTabIndex: number;
@Watch('onTabIndexChange')
onTabIndexChange() {
this.showPage();
}
showPage() {
// Code to run when tab appears
}
}
Top comments (0)