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)