Read the original article:How to transfer data between pages via a @Link
Context
In HarmonyOS application development, developers often need to transfer data between pages. A common use case is when data is sent from one page and needs to be used inside a specific component of the target page. However, components cannot directly receive parameters in such cases. To solve this, the @Link decorator is used to bind the passed data to the component.
Description
When navigating from one page to another, the data passed as parameters should be made available inside a custom component (e.g., DrinkDescriptionView) within the target page (DrinkDescriptionPage). Since parameters cannot be injected directly into the component, the @Link mechanism allows seamless data binding between the parent page and its child components.
Solution / Approach
DrinksGridView: When a user clicks on an item, router.pushUrl is used to navigate to DrinkDescriptionPage, passing the selected Drink object as a parameter.
import {Drink} from '../viewmodel/Drink' import {drinkList} from '../viewmodel/DrinkList' import router from '@ohos.router'; @Component export struct DrinksGridView { @State searchText: string = '' @State filteredDrinks: Drink[] = drinkList @State buttonSize: number = 100 timer: number = 0 @State loadingState: boolean = false @State createCount: number = 0; @State result: boolean = false; private filterDrinks() { if (this.searchText.trim() === '') { this.filteredDrinks = drinkList } else { const searchTerm = this.searchText.toLowerCase() this.filteredDrinks = drinkList.filter(item => item.name.toLowerCase().includes(searchTerm) || (item.description && item.description.toLowerCase().includes(searchTerm)) ) } } build() { Column() { Row() { TextInput({ placeholder: '🔍 Search Drink...'}) .width('92%') .height(56) .margin({ top: 12, bottom: 8 }) .padding(10) .fontSize(18) .backgroundColor('#FFFFFF') .borderRadius(16) .onChange((value: string) => { this.searchText = value this.filterDrinks() }) } Grid() { ForEach(this.filteredDrinks, (item: Drink) => { GridItem() { Column() { Image(item.image) .width('100%') .aspectRatio(1) .objectFit(ImageFit.Cover) .borderRadius(12) Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) .margin({ top: 4 }) } .padding(8) } .backgroundColor(Color.White) .border({ width: 2, color: '#e0e0e0', radius: 12 }) .shadow({ radius: 4, color: '#20000000', offsetX: 1, offsetY: 1 }) .margin(4) .onClick(() => { router.pushUrl({ url: 'pages/DrinkDescriptionPage', params: item }) }) }) } .columnsTemplate('1fr 1fr') .width('100%') .height('100%') .layoutWeight(1) } .width('100%') .height('100%') } } DrinkDescriptionPage: In the aboutToAppear lifecycle method, the parameter is retrieved using router.getParams() and stored in a @State variable. This state is then linked to the DrinkDescriptionView component using @Link.
import router from '@ohos.router'; import { Drink } from '../viewmodel/Drink' import { DrinkDescriptionView } from '../view/DrinkDescriptionView' @Entry @Component struct DrinkDescriptionPage { @State drink: Drink | null = null; aboutToAppear() { const params = router.getParams() as Drink; if (params) { this.drink = { name: params.name, image: params.image, description: params.description, degree: params.degree } } } build() { Column() { if (this.drink) { DrinkDescriptionView({ drink: $drink }) } else { } } .width('100%') .height('100%') .backgroundColor('#F5F5F5') .alignItems(HorizontalAlign.Center) } } DrinkDescriptionView: With the @Link decorator, the component receives the Drink object from the parent page and displays its content (image, name, description, degree). A back button allows navigation back to the grid view.
import {Drink} from '../viewmodel/Drink'; import router from '@ohos.router'; @Component export struct DrinkDescriptionView { @Link drink: Drink build() { Column() { if (this.drink) { Column() { Image(this.drink.image) .width(120) .height(120) .objectFit(ImageFit.Cover) .borderRadius(8) .margin({ bottom: 10 }) Text(this.drink.name) .fontSize(18) .fontWeight(FontWeight.Bold) .margin({ bottom: 4 }) Text(`%${this.drink.degree} alcohol`) .fontSize(14) .fontColor('#666') } .width('40%') .padding(10) .margin({top: 20}) .backgroundColor('#FFF') .borderRadius(12) .shadow({ radius: 6, color: '#10000000' }) Scroll() { Text(this.drink.description) .fontSize(16) .lineHeight(24) .padding(20) } .margin({ top: 20 }) .width('90%') .height('40%') .borderRadius(12) .backgroundColor('#FFFFFF') .scrollable(ScrollDirection.Vertical) .scrollBar(BarState.On) Column() { Button('LET THE CHALLENGE BEGINS') .width('90%') .height(50) .fontSize(18) .fontWeight(FontWeight.Bold) .backgroundColor('#2E7D32') .fontColor(Color.White) .margin({ top: 20, bottom: 10 }) .stateEffect(true) .shadow({ radius: 4, color: '#40000000' }) .onClick(() => { router.replaceUrl({ url: 'pages/ChallengePage', params: this.drink }) }) Button('BACK TO MENU') .width('90%') .height(50) .fontSize(18) .fontWeight(FontWeight.Bold) .backgroundColor('#F9A825') .margin({ bottom: 20 }) .stateEffect(true) .shadow({ radius: 4, color: '#40000000' }) .onClick(() => { router.back(); }) } .width('100%') .margin({ top: 10, bottom: 20 }) } else { } } .width('100%') .height('100%') .backgroundColor('#F5F5F5') .alignItems(HorizontalAlign.Center) } } Drink: A represantative model for Drink object
export interface Drink { name: string, description: string, image: Resource, degree: number } This approach ensures smooth data transfer from page to component.
Key Takeaways
Use @Link to bind state from a parent page to a child component.
Use router.pushUrl to pass parameters when navigating between pages.
Retrieve parameters on the target page with router.getParams().
Combine @State (in the parent page) and @Link (in the child component) for effective data sharing.
Additional Resources
https://developer.huawei.com/consumer/en/doc/harmonyos-guides/ide-arktsdoc-link
https://developer.huawei.com/consumer/en/doc/harmonyos-references/ts-container-grid
Top comments (0)