目录

HarmonyOS-Next-状态管理-状态修饰器实践

HarmonyOS Next 状态管理:!! 状态修饰器实践

目录

一. !! 修饰器概述

!! 是一种语法糖,用于实现父子组件之间的双向数据绑定。它主要用于初始化子组件中的 @Param@Event ,其中 @Event 的命名规则为 $ + @Param 属性名

  • 双向绑定 :当父子组件中使用 !! 语法时,父组件的数据变化会同步到子组件,子组件的数据变化也会同步到父组件。
  • 单向绑定 :如果父组件未使用 !! 语法,则数据流是单向的,父组件的变化不会同步到子组件。

二. !! 场景事件

2.1 简单使用!!实现双向绑定

@Entry

@ComponentV2

struct Index {

@Local name: string = “父组件”

build() {

Column({space: 20}) {

Text( ${this.name} )

Button(‘父组件中修改值’)

.onClick(() => {

this.name = 父组件中:${Math.round(Math.random() * 100)}

})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

ChildComponent({cName: this.name!!})

}

}

}

@ComponentV2

struct ChildComponent {

@Param cName: string = “子组件”

@Event $cName: (name: string) => void

build() {

Column() {

Text( ${this.cName} )

Button(‘子组件中修改值’)

.onClick(() => {

this.

c N a m e ( ‘ 子组件中: cName(`子组件中:

c

N

am

e

(

子组件中: {Date().toString()}`)

})

}

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2Fc939bdaeaedf406583b414d9554362eb~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524627%26x-orig-sign%3DQDERcvrSPds5YtmMAlJjjli5%252Fhc%253D&pos_id=img-nG5H1vvo-1741921294442

关键点

  • 父组件更新 :父组件中状态变量的变化会同步到子组件。
  • 子组件更新 :子组件中状态变量的变化会同步到父组件。
  • 命名规则@Event 的命名格式为 $ + @Param 属性名
  • 语法糖 :父组件中传递参数时需在变量后添加 !!
2.2 !! 的声明与使用差异

@Entry

@ComponentV2

struct Index {

@Local name: string = “父组件”

build() {

Column({space: 20}) {

Text( ${this.name} )

Button(‘父组件中修改值’)

.onClick(() => {

this.name = 父组件中:${Math.round(Math.random() * 100)}

})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

ChildComponent({cName: this.name!!})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

AnotherChildComponent({aName: this.name})

}

}

}

@ComponentV2

struct ChildComponent {

@Param cName: string = “子组件”

@Event $cName: (name: string) => void

build() {

Column() {

Text( ${this.cName} )

Button(‘子组件中修改值’)

.onClick(() => {

this.

c N a m e ( ‘ 子组件中: cName(`子组件中:

c

N

am

e

(

子组件中: {Date().toString()}`)

})

}

}

}

@ComponentV2

struct AnotherChildComponent {

@Param aName: string = “another子组件”

@Event $aName: (name: string) => void = (name: string) => {}

build() {

Column() {

Text( another: ${this.aName} )

Button(‘another子组件中修改值’)

.onClick(() => {

this.$aName( another中:abc )

})

}

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2Fae0fcbe99d524b528307d844063279cd~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524627%26x-orig-sign%3Dxkf5%252FQWGg5f3Hmebp3Jlt7hUaC8%253D&pos_id=img-AsGvQQuT-1741921294444

关键点

  • 双向绑定 :使用 !! 语法时,父子组件之间的数据变化是双向的。
  • 单向绑定 :未使用 !! 语法时,数据流是单向的,子组件无法将数据变化同步回父组件。
2.3 多层组件数据更新

在日常开发中,通常会封装或抽象出小型可复用的组件,这涉及到多层级组件之间的数据传递。

2.3.1  数据的层级传递

@Entry

@ComponentV2

struct Index {

@Local name: string = “父组件”

build() {

Column({space: 20}) {

Text( ${this.name} )

Button(‘父组件中修改值’)

.onClick(() => {

this.name = 父组件中:${Math.round(Math.random() * 100)}

})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

ChildComponent({cName: this.name!!})

}

}

}

@ComponentV2

struct ChildComponent {

@Param cName: string = “子组件”

@Event $cName: (name: string) => void

build() {

Column({space: 20}) {

Text( ${this.cName} )

Button(‘子组件中修改值’)

.onClick(() => {

this.

c N a m e ( ‘ 子组件中: cName(`子组件中:

c

N

am

e

(

子组件中: {Date().toString()}`)

})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

ItemComponent({iName: this.cName!!})

}

}

}

@ComponentV2

struct ItemComponent {

@Param iName: string = “iName”

@Event $iName: (name: string) => void = (name: string) => {}

build() {

Column({space: 20}) {

Text( item:${this.iName} )

Button(‘item更新数据’)

.onClick(() => {

this.

i N a m e ( ‘ i t e m : iName(`item:

i

N

am

e

(

i

t

e

m

: {Math.round(Math.random() * 100)`)

})

}

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2F9bf70a1a8d01480c957ff710e8cf6ecc~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524627%26x-orig-sign%3DcdYlnGF1LYCB%252Fr3KanrXa4b%252F%252BcU%253D&pos_id=img-Y5XRoyuT-1741921294444

关键点

  • 数据传递 :数据可以从父组件传递到子组件,再到更深层级的组件。
  • UI 刷新 :只有父组件和直接子组件的数据更新会触发 UI 刷新。
  • 局限性!! 语法糖不支持多层级组件之间的双向数据绑定。
2.3.1  实现数据的多层级传递

@Entry

@ComponentV2

struct Index {

@Local name: string = “父组件”

build() {

Column({space: 20}) {

Text( ${this.name} )

Button(‘父组件中修改值’)

.onClick(() => {

this.name = 父组件中:${Math.round(Math.random() * 100)}

})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

ChildComponent({cName: this.name!!})

}

}

}

@ComponentV2

struct ChildComponent {

@Param cName: string = “子组件”

@Event $cName: (name: string) => void

build() {

Column({space: 20}) {

Text( ${this.cName} )

Button(‘子组件中修改值’)

.onClick(() => {

this.

c N a m e ( ‘ 子组件中: cName(`子组件中:

c

N

am

e

(

子组件中: {Date().toString()}`)

})

Line().width(‘100%’).height(1).backgroundColor(Color.Gray)

ItemComponent({iName: this.cName,

KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …          this. cName(name)

}})

}

}

}

@ComponentV2

struct ItemComponent {

@Param iName: string = “iName”

@Event $iName: (name: string) => void = (name: string) => {}

build() {

Column({space: 20}) {

Text( item:${this.iName} )

Button(‘item更新数据’)

.onClick(() => {

this.

i N a m e ( ‘ i t e m : iName(`item:

i

N

am

e

(

i

t

e

m

: {Math.round(Math.random() * 100)}`)

})

}

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2Faa575b9744534808acff8e92e7a0c441~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524627%26x-orig-sign%3D5Zjm0kyAL0vloC9DpKsbCwDE5Ms%253D&pos_id=img-c1xOOSVC-1741921294444

关键点

  • 回调机制 :通过回调函数实现多层级组件之间的数据传递。
  • 双向绑定!! 语法糖仅支持父子组件之间的双向绑定,多层级组件间的数据传递需手动实现。
  • 灵活性 :通过回调函数,可以实现更复杂的数据流控制。

三、总结

  1. 双向绑定!! 语法糖简化了父子组件之间的双向数据绑定,提升了开发效率。
  2. 单向绑定 :未使用 !! 时,数据流是单向的,子组件无法将数据变化同步回父组件。
  3. 多层级数据传递!! 语法糖不支持多层级组件之间的双向绑定,需通过回调函数手动实现。

通过合理使用 !! 语法糖和回调机制,可以有效管理组件之间的数据流,确保数据的同步更新和 UI 的正确刷新。