鴻蒙Next中@Observed和@ObjectLink的使用方法

一、概述

在鴻蒙Next中,@Observed@ObjectLink裝飾器用于處理嵌套類對象屬性變化,實(shí)現(xiàn)雙向數(shù)據(jù)同步,彌補(bǔ)了其他裝飾器只能觀察一層變化的局限。從API version 9開始,這兩個(gè)裝飾器支持在ArkTS卡片中使用,從API version 11開始,支持在元服務(wù)中使用。

(一)功能特性

  1. @Observed用于標(biāo)記類,使其創(chuàng)建的實(shí)例能被觀察到屬性變化,主要用于嵌套類場景。
  2. @ObjectLink裝飾子組件中的狀態(tài)變量,接收@Observed裝飾的類的實(shí)例,與父組件中對應(yīng)的狀態(tài)變量建立雙向數(shù)據(jù)綁定。

二、裝飾器說明

(一)@Observed類裝飾器

  1. 參數(shù):無。
  2. 類裝飾器:用于修飾class,需放在class定義前,通過new創(chuàng)建類對象。

(二)@ObjectLink變量裝飾器

  1. 參數(shù):無。
  2. 允許裝飾的變量類型
    • 必須為被@Observed裝飾的class實(shí)例,且必須指定類型。
    • 不支持簡單類型,若需使用簡單類型可考慮@Prop。
    • 支持繼承Date、Array的class實(shí)例,API11及以上支持繼承Map、Set的class實(shí)例,API11及以上還支持@Observed裝飾類和undefined或null組成的聯(lián)合類型。
    • 變量屬性可改變,但變量自身分配不允許,即該裝飾器裝飾的變量只讀,不能被重新賦值(整體替換除外,但要在父組件進(jìn)行)。

三、變量的傳遞/訪問規(guī)則

  1. 從父組件初始化
    • 必須指定。
    • 初始化@ObjectLink裝飾的變量需同時(shí)滿足以下條件:
      • 類型必須是@Observed裝飾的class。
      • 初始化數(shù)值需是數(shù)組項(xiàng)或class的屬性。
      • 同步源的class或數(shù)組必須是@State、@Link@Provide、@Consume或者@ObjectLink裝飾的數(shù)據(jù)。
  2. 與源對象同步:雙向同步。
  3. 可以初始化子組件:允許,可用于初始化常規(guī)變量、@State、@Link、@Prop@Provide

四、觀察變化和行為表現(xiàn)

(一)觀察變化

  1. @Observed裝飾的類
    • 若屬性為非簡單類型(如class、Object或數(shù)組),也需被@Observed裝飾,否則其屬性變化無法觀察到。
  2. @ObjectLink裝飾的變量
    • 可觀察到屬性數(shù)值的變化(屬性指Object.keys返回的所有屬性)。
    • 若數(shù)據(jù)源是數(shù)組,可觀察到數(shù)組item的替換;若數(shù)據(jù)源是class,可觀察到class的屬性變化。
    • 對于繼承Date、Map、Set的class實(shí)例,可分別觀察到相應(yīng)類型的整體賦值及通過接口更新值的操作(如Date的日期屬性更新、Map的鍵值更新、Set的元素更新等)。

(二)框架行為

  1. 初始渲染
    • @Observed裝飾的class的實(shí)例被不透明代理對象包裝,代理其屬性的setter和getter方法。
    • 子組件中@ObjectLink裝飾的變量從父組件初始化,接收@Observed裝飾的class的實(shí)例,@ObjectLink的包裝類將自己注冊給@Observed class。
  2. 屬性更新
    • 當(dāng)@Observed裝飾的class屬性改變時(shí),執(zhí)行代理的setter和getter,遍歷依賴它的@ObjectLink包裝類,通知數(shù)據(jù)更新。

五、使用場景示例

(一)嵌套對象

  1. 定義了Bag、User、Book、BookName等類,均被@Observed裝飾,形成嵌套對象結(jié)構(gòu)。
  2. ViewA、ViewC子組件中通過@ObjectLink接收父組件ViewB@State變量的屬性(如Bag實(shí)例或BookName實(shí)例),實(shí)現(xiàn)雙向同步。
  3. ViewB中對user.bagchild.bookName.size等屬性的修改,能在相關(guān)子組件中同步更新。注意@ObjectLink變量只讀,不能進(jìn)行整體賦值操作(如this.bookName = new bookName(...)),但可更改成員屬性(如this.bookName.size += 1)。

(二)對象數(shù)組

  1. 定義Info類被@Observed裝飾,Parent組件中有@State裝飾的Info[]數(shù)組。
  2. Child子組件通過@ObjectLink接收Info實(shí)例,實(shí)現(xiàn)雙向同步。
  3. Parent中對數(shù)組的操作(如push、shift、修改數(shù)組項(xiàng)屬性等)會(huì)觸發(fā)不同的更新效果,涉及ForEach的重新執(zhí)行和相關(guān)子組件的刷新,而對于@State無法觀察到的第二層屬性變化(如Info類中的info屬性),由于Info@Observed裝飾,可被@ObjectLink觀察到并同步更新。

(三)二維數(shù)組

  1. 聲明StringArray類繼承Array<string>并被@Observed裝飾,通過new創(chuàng)建實(shí)例。
  2. IndexPage組件中定義@State裝飾的Array<StringArray>二維數(shù)組,ItemPage子組件通過@ObjectLink接收StringArray實(shí)例,實(shí)現(xiàn)雙向同步。
  3. IndexPage中對二維數(shù)組元素的操作(如push)會(huì)觸發(fā)相應(yīng)的UI更新。

(四)繼承Map類(API11及以上)

  1. 定義Info類包含MyMap<number, string>類型的屬性,MyMap類需被@Observed裝飾(此處假設(shè)已定義)。
  2. 在相關(guān)組件中,通過@ObjectLink實(shí)現(xiàn)對MyMap類型數(shù)據(jù)的雙向同步,點(diǎn)擊按鈕改變MyMap屬性時(shí),視圖會(huì)隨之刷新。同理,對于繼承Set類也類似(可參考繼承Set類部分的示例)。

六、限制條件

  1. 使用@Observed裝飾class會(huì)改變其原始原型鏈,與其他類裝飾器一起使用可能導(dǎo)致問題。
  2. @ObjectLink裝飾器不能在@Entry裝飾的自定義組件中使用。
  3. @ObjectLink裝飾的變量類型需為顯式的被@Observed裝飾的類,未指定類型或類型錯(cuò)誤在編譯期會(huì)報(bào)錯(cuò)。
  4. @ObjectLink裝飾的變量不能本地初始化,只能通過構(gòu)造參數(shù)從父組件傳入初始值,否則編譯報(bào)錯(cuò)。且變量只讀,賦值操作會(huì)導(dǎo)致運(yùn)行時(shí)報(bào)錯(cuò)(除在父組件進(jìn)行整體替換)。

七、常見問題及注意事項(xiàng)

(一)在子組件中給@ObjectLink裝飾的變量賦值

不允許直接賦值,會(huì)導(dǎo)致同步鏈打斷和運(yùn)行時(shí)報(bào)錯(cuò),應(yīng)在父組件進(jìn)行整體替換或僅修改其屬性。

(二)基礎(chǔ)嵌套對象屬性更改失效

確保嵌套對象中的類及其屬性(非簡單類型)都被@Observed裝飾,否則屬性變化無法被觀察到。

(三)復(fù)雜嵌套對象屬性更改失效

如二維數(shù)組等復(fù)雜嵌套結(jié)構(gòu),同樣要保證各層級相關(guān)類都被@Observed裝飾,以實(shí)現(xiàn)屬性變化的觀察和同步。

(四)@Prop@ObjectLink的差異

@Prop裝飾的變量與數(shù)據(jù)源單向同步,允許本地更改但父組件數(shù)據(jù)源更新時(shí)本地修改會(huì)被覆蓋;@ObjectLink裝飾的變量與數(shù)據(jù)源雙向同步,相當(dāng)于指向數(shù)據(jù)源的指針,只讀且不能重新賦值(整體替換在父組件進(jìn)行)。

(五)在@Observed裝飾類的構(gòu)造函數(shù)中延時(shí)更改成員變量

不建議在構(gòu)造函數(shù)中進(jìn)行延時(shí)更改成員變量的操作,可能導(dǎo)致預(yù)期外的行為,應(yīng)在合適的時(shí)機(jī)修改屬性以確保變化可被觀察和同步。

(六)@ObjectLink數(shù)據(jù)源更新時(shí)機(jī)

數(shù)據(jù)源(@Observed裝飾的類實(shí)例)的屬性變化會(huì)觸發(fā)@ObjectLink裝飾變量的更新,從而更新相關(guān)UI組件,但要注意同步機(jī)制和觸發(fā)條件,如ForEach的更新機(jī)制對數(shù)組操作的影響等。

(七)使用a.b(this.object)形式調(diào)用,不會(huì)觸發(fā)UI刷新

當(dāng)@ObjectLink裝飾的變量是Object類型,且在build方法內(nèi)通過a.b(this.object)形式調(diào)用(如靜態(tài)方法或組件內(nèi)部方法修改Object屬性)時(shí),無法觸發(fā)UI刷新。解決方法是先對變量進(jìn)行賦值,使修改操作作用于帶有Proxy代理的變量,從而實(shí)現(xiàn)UI刷新。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容