HarmonyNote.TOP鸿蒙开发笔记

@Provide@Consume只能作用在同一棵组件树中

应用里有个需求是从A页面打开一个@CustomDialog修饰的弹窗,弹窗里有一个按钮点击后通过router.pushUrl的方式跳转到B页面,在B页面里修改一个状态变量,然后点击B页面的返回按钮通过router.back的方式返回到A页面,A页面需要监测被修改的状态变量。一开始是在A页面用@Provide修改了变量C,在B页面用@Consume接收A页面的状态变量,部署到真机上运行后跳转B页面的时候APP直接闪退重启,查看Log面板的FaultLog错误如下:

Device info:nova 14
Build info:TLR-AL00 5.0.1.125(SP5C00E125R3P5)
Fingerprint:1220b3ac473651e1884e5f199aa9aa544b93dfabdc1d5d77e424233d4a56a200
Module name:com.xxx.XXOOProject
Version:1.0.0
VersionCode:1000000
PreInstalled:No
Foreground:Yes
Pid:9049
Uid:20020195
Reason:ReferenceError
Error name:ReferenceError
Error message:@Component 'SetUpThemePage'[54] missing @Provide property with name changeThemeName.
          Fail to resolve @Consume(changeThemeName).
Stacktrace:
    at initializeConsume (/usr1/hmos_for_system/src/increment/sourcecode/foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/stateMgmt.js:6833:1)
    at SetUpThemePage (entry/src/main/ets/pages/setting_page/SetUpThemePage.ets:14:45)
    at anonymous (entry|entry|1.0.0|src/main/ets/pages/setting_page/SetUpThemePage.ts:298:26)
    at anonymous (entry/src/main/ets/pages/custom_dialog/ArticleListCustomDialog.ets:58:13)

B页面missing @Provide property with name changeThemeName,Fail to resolve @Consume(changeThemeName)。也就是B页面无法找到状态变量C的提供者,与AI交流后得知提供者(@Provide)和消费者(@Consume)必须在同一个组件树中,即它们需要有共同的祖先(提供者必须是消费者的祖先)。通过router路由跳转页面显然不在同一颗组件树中,因此我改用AppStorage内存来更新状态变量,并且成功了。以下是@Provide@Consume作用域的具体细节:

组件树层级关系​:
       @Provide装饰的变量在组件树上向下传递,可以被其子孙组件中的@Consume装饰的变量所接收。
       这种传递不受限于直接的父子关系,可以跨越多层。
​单组件内​:
       在同一个组件内,不能同时使用@Provide和@Consume装饰同一个变量(即不能自己提供给自己消费)。
​跨组件传递​:
       提供者(@Provide)和消费者(@Consume)必须在同一个组件树中,即它们需要有共同的祖先(提供者必须是消费者的祖先)。
​多层级传递​:
       如果中间层组件也使用@Provide装饰了同名的变量,那么它会覆盖祖先提供的值,并且向下传递自己的值。此时,子孙组件中的@Consume会 
       接收到最近祖先的@Provide的值。

归纳总结:

1、@Provide和@Consume用于跨组件层级的数据传递,提供者在上,消费者在下。
2、作用范围是整个组件树,但仅限于有共同祖先的组件之间。
3、如果中间组件提供了同名的@Provide,则它会覆盖祖先的值,并成为新的提供者。
4、不能在同一组件内同时使用@Provide和@Consume装饰同一个变量(但可以在同一组件的不同变量上使用)。

在大型项目中,过度使用@Provide和@Consume可能会使数据流难以追踪,因此建议在需要跨多层传递数据时使用,对于父子组件通信,优先使用@Prop和@Link。