UI状態管理
@Entry (エントリーポイント)
ページには一つだけ@Entryが存在します。
@Entry
@Component
struct IndexPage {
@State userDetail: string = ''
aboutToAppear() {
console.info('IndexPage 即将显示')
// サンプル1:AppStorageからデータ取得
this.userDetail = AppStorage.get<string>('userName', '匿名ユーザー')
// サンプル2:ネットワークリクエストのシミュレーション
this.loadUserData()
// サンプル3:埋点統計
analyticsService.pageView('HomePage')
}
async loadUserData() {
try {
const data = await fetchUserApi()
console.info('ユーザーデータ読み込み完了:', data)
this.userDetail = data.name
} catch (error) {
console.error('読み込み失敗:', error)
}
}
build() {
Column() {
Text(`ユーザー:${this.userDetail}`)
.fontSize(18)
.margin(20)
}
.width('100%')
.height('100%')
}
}
@Component (コンポーネント)
HarmonyOSのライフサイクルは、@Componentと@Entryで分類されます。それぞれカスタムコンポーネントとページのライフサイクルを指します。
コンポーネントの特徴:
- ページには一つだけ@Entryがあります。
- ページは複数のコンポーネントを含むことができます。
- 各コンポーネントはbuildメソッドを持ち、UIを更新する必要があります。
- コンポーネント内部で他のコンポーネントを呼び出すことができます。
@Builder (ビルド関数)
1. 引数なしの@Builder
@Builder
function simpleTextBuilder() {
Text('こんにちは世界')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Blue)
}
2. 引数付きの@Builder
@Builder
function paramTextBuilder(text: string, size: number, color: Color) {
Text(text)
.fontSize(size)
.fontColor(color)
.fontWeight(FontWeight.Medium)
}
3. 条件付きの@Builder
@Builder
function conditionalTextBuilder(score: number) {
if (score >= 90) {
Text('優秀')
.fontColor(Color.Green)
} else if (score >= 60) {
Text('合格')
.fontColor(Color.Orange)
} else {
Text('不合格')
.fontColor(Color.Red)
}
}
4. ループ付きの@Builder
@Builder
function listTextBuilder(items: string[]) {
Column() {
ForEach(items, (item: string) => {
Text(item)
.fontSize(16)
.margin(5)
})
}
}
@State (ステート)
@Stateで修飾された変数は、UIレンダリングと結びつきます。状態が変化すると、UIも対応して更新されます。
@Entry
@Component
struct CounterExample {
@State count: number = 0
build() {
Column({ space: 20 }) {
Text(`現在のカウント: ${this.count}`)
.fontSize(30)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Blue)
Button('カウントアップ +1')
.onClick(() => {
this.count++
})
.width(200)
.height(50)
.backgroundColor(Color.Green)
Button('カウントダウン -1')
.onClick(() => {
this.count--
})
.width(200)
.height(50)
.backgroundColor(Color.Orange)
Button('リセット')
.onClick(() => {
this.count = 0
})
.width(200)
.height(50)
.backgroundColor(Color.Red)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
@Prop (プロパティ)
単方向データフロー:親コンポーネントから子コンポーネントへデータが流れます。子コンポーネントは親コンポーネントのデータを直接変更できません。
// 簡単な型
@Prop itemCount: number;
// 複雑な型
@Prop title: Model;
class Info {
value: string;
constructor(value: string) {
this.value = value;
}
}
class Model {
value: string;
info: Info;
constructor(value: string, info: Info) {
this.value = value;
this.info = info;
}
}
@Prop bookModel: Model;
// 第一層の変更は観測可能
this.bookModel.value = '新しいタイトル';
// 第二層の変更は観測不可
this.bookModel.info.value = '新しい情報';
@Link (双方向バインディング)
双方向データバインディングにより、親子コンポーネント間でデータが同期されます。
@Entry
@Component
struct ParentComponent {
@State parentMessage: string = "Hello from Parent"
build() {
Column({ space: 20 }) {
Text("親コンポーネントのメッセージ")
.fontSize(18)
.text(this.parentMessage)
Button('親コンポーネントのメッセージを変更')
.onClick(() => {
this.parentMessage = "親コンポーネントのメッセージが更新されました"
})
.width(200)
ChildComponent({
message: $parentMessage
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}
@Component
struct ChildComponent {
@Link message: string
build() {
Column({ space: 15 }) {
Text(`親コンポーネントからのメッセージ: ${this.message}`)
Button('メッセージをローカルに変更')
.onClick(() => {
this.message += " (ローカル変更)"
})
.width(200)
}
.padding(15)
.border({ width: 1, color: Color.Gray })
.borderRadius(10)
.margin({ top: 20 })
}
}
@Provide / @Consume (データ提供と消費)
@Provideと@Consumeは、多階層の親子コンポーネント間でデータを効率的に伝達するために使用されます。
@Entry
@Component
struct ParentComponent {
@Provide globalCount: number = 0
build() {
Column() {
Text(`グローバルカウント: ${this.globalCount}`)
.onClick(() => {
this.globalCount++
})
ChildComponent()
}
.width('100%')
.height('100%')
.padding(20)
}
}
@Component
struct ChildComponent {
@Consume globalCount: number
build() {
Column() {
Text(`受け取ったグローバルカウント: ${this.globalCount}`)
.onClick(() => {
this.globalCount++
})
}
.width('100%')
.height('100%')
.padding(20)
}
}