隨著 Flutter 的發(fā)展,這些年 Flutter 上的狀態(tài)管理框架如“雨后春筍”般層出不窮燕偶,而近一年以來(lái)最受官方推薦的狀態(tài)管理框架無(wú)疑就是 Riverpod
喝噪,甚至已經(jīng)超過(guò)了 Provider
,事實(shí)上 Riverpod
官方也稱自己為 “Provider
指么,但與眾不同”酝惧。
Provider
本身用它自己的話來(lái)說(shuō)是 “InheritedWidget
的封裝,但更簡(jiǎn)單且復(fù)用能力更強(qiáng)伯诬⊥泶剑” ,而Riverpod
就是在Provider
的基礎(chǔ)上重構(gòu)了新的可能盗似。
關(guān)于過(guò)去一年?duì)顟B(tài)管理框架的對(duì)比可以看 《2021 年的 Flutter 狀態(tài)管理:如何選擇哩陕?》 , 本文主要是帶你解剖 RiverPod
的內(nèi)部是如何實(shí)現(xiàn)赫舒,理解它的工作原理悍及,以及如何做到比 Provider
更少的模板和不依賴 BuildContext
。
前言
如果說(shuō) Riverpod
最明顯的特點(diǎn)是什么接癌,那就是外部不依賴 BuildContext
(其實(shí)就是換了另外一種依賴形態(tài))并鸵,因?yàn)椴灰蕾?BuildContext
,所以它可以比較簡(jiǎn)單做到類似如下的效果:
也就是 Riverpod
中的 Provider
可以隨意寫成全局扔涧,并且不依賴 BuildContext
來(lái)編寫我們需要的業(yè)務(wù)邏輯园担。
?? 提前聲明下,這里和后續(xù)的
Provider
枯夜,和第三方庫(kù)provider
沒(méi)有關(guān)系弯汰。
那 Riverpod
具體內(nèi)部是怎么實(shí)現(xiàn)的呢?接下來(lái)讓我們開(kāi)始探索 Riverpod
的實(shí)現(xiàn)原理湖雹。
Riverpod
的實(shí)現(xiàn)相對(duì)還是比較復(fù)雜咏闪,所以還耐心往下看,因?yàn)楸酒侵鸩浇馕觯?strong>所以如果看的過(guò)程有些迷惑可以先不必在意摔吏,通篇看完再回過(guò)來(lái)翻閱可能就會(huì)更加明朗鸽嫂。
從 ProviderScope 開(kāi)始
在 Flutter 里只要使用了狀態(tài)管理纵装,就一定避不開(kāi) InheritedWidget
, Riverpod 里也一樣据某,在 Riverpod 都會(huì)有一個(gè) ProviderScope
橡娄, 一般只需要注冊(cè)一個(gè)頂級(jí)的 ProviderScope
。
如果對(duì)于 InheritedWidget 還有疑問(wèn)癣籽,可以看我掘金:《全面理解State與Provider》
先從一個(gè)例子開(kāi)始挽唉,如下圖所示,是官方的一個(gè)簡(jiǎn)單的例子筷狼,可以看到這里:
- 嵌套一個(gè)頂級(jí)
ProviderScope
瓶籽; - 創(chuàng)建了一個(gè)全局的
StateProvider
; - 使用
ConsumerWidget
的ref
對(duì)創(chuàng)建的counterProvider
進(jìn)行read
從而讀取 State 埂材,獲取到int
值進(jìn)行增加 塑顺; - 使用另一個(gè)
Consumer
的ref
對(duì)創(chuàng)建的counterProvider
進(jìn)行watch
,從而讀取到每次改變后的int
值俏险;
很簡(jiǎn)單的例子严拒,可以看到?jīng)]有任何 of(context)
, 而全局的 counterProvider
里的數(shù)據(jù)寡喝,就可以通過(guò) ref
進(jìn)行 read/watch糙俗,并且正確地讀取和更新。
那這是怎么實(shí)現(xiàn)的呢预鬓?
counterProvider
又是如何被注入到ProviderScope
里面巧骚?為什么沒(méi)有看到context
? 帶著這些疑問(wèn)我們繼續(xù)往下探索格二。
首先我們看 ProviderScope
劈彪,它是唯一的頂級(jí) InheritedWidget
,所以 counterProvider
必定是被存放在這里:
在 RiverPod 里顶猜,
ProviderScope
最大的作用就是提供一個(gè)ProviderContainer
沧奴。
更具體地說(shuō),就是通過(guò)內(nèi)部嵌套的 UncontrolledProviderScope
提供长窄,所以到這里我們可以知道:ProviderScope
可以往下提供狀態(tài)共享滔吠,因?yàn)樗鼉?nèi)部有一個(gè) InheritedWidget
,而主要往下共享的是 ProviderContainer
這個(gè)類挠日。
所以首先可以猜測(cè):我們定義的各種 Providers疮绷, 比如上面的 counterProvider
, 都是被存到 ProviderContainer
中嚣潜,然后往下共享冬骚。
事實(shí)上官方對(duì)于
ProviderContainer
的定義就是:用于保存各種 Providers 的 State ,并且支持 override 一些特殊 Providers 的行為。
ProviderContainer
這里出現(xiàn)了一個(gè)新的類只冻,叫 ProviderContainer
庇麦,其實(shí)一般情況下使用 RiverPod 你都不需要知道它,因?yàn)槟悴粫?huì)直接操作和使用它喜德,但是你使用 RiverPod 的每個(gè)行為都會(huì)涉及到它的實(shí)現(xiàn)山橄,例如 :
-
ref.read
會(huì)需要它的Result read<Result>
; -
ref.watch
會(huì)需要它的ProviderSubscription<State> listen<State>
住诸; -
ref.refresh
會(huì)需要它的Created refresh<Created>
就算是各種 Provider
的保存和讀取基本也和它有關(guān)系驾胆,所以它作為一個(gè)對(duì)各種 Provider
的內(nèi)部管理的類涣澡,實(shí)現(xiàn)了 RiverPod 里很關(guān)鍵的一些邏輯贱呐。
“Provider” 和 “Element”
那前面我們知道 ProviderScope
往下共享了 ProviderContainer
之后,Provider
又是怎么工作的呢入桂?為什么 ref.watch
/ ref.read
會(huì)可以讀取到它 Provider
里的值奄薇?
繼續(xù)前面的代碼,這里只是定義了 StateProvider
抗愁,并且使用了 ref.watch
馁蒂,為什么就可以讀取到里面的 state
值?
首先 StateProvider
是一個(gè)特殊的 Provider
蜘腌,在它的內(nèi)部還有一個(gè)叫 _NotifierProvider
的幫它實(shí)現(xiàn)了一層轉(zhuǎn)換沫屡,所以我們先用最基礎(chǔ)的 Provider
類作為分析對(duì)象。
基本是各種類似的 Provider
都是 ProviderBase
的子類撮珠,所以我們先解析 ProviderBase
沮脖。
在 RiverPod 內(nèi)部,每個(gè) ProviderBase
的子類都會(huì)有其對(duì)應(yīng)的 ProviderElementBase
子類實(shí)現(xiàn) 芯急,例如前面代碼使用的 StateProvider
是 ProviderBase
的之類勺届,同樣它也有對(duì)應(yīng)的 StateProviderElement
是 ProviderElementBase
的子類;
所以 RiverPod 里基本是每一個(gè) “Provider” 都會(huì)有一個(gè)自己的 “Element” 娶耍。
??這里的 “Element” 不是 Flutter 概念里三棵樹(shù)的
Element
免姿,它是 RiverPod 里Ref
對(duì)象的子類。Ref
主要提供 RiverPod 內(nèi)的 “Provider” 之間交互的接口榕酒,并且提供一些抽象的生命周期方法胚膊,所以它是 RiverPod 里的獨(dú)有的 “Element” 單位。
那 “Provider” 和 “Element” 的作用是什么想鹰?
首先紊婉,在上面例子里我們構(gòu)建 StateProvider
時(shí)傳入的 (ref) => 0
,其實(shí)就是 Create<State, StateProviderRef<State>>
函數(shù)杖挣,我們就從這個(gè) Create
函數(shù)作為入口來(lái)探索肩榕。
Create<T, R extends Ref> = T Function(R ref)
RiverPod 里構(gòu)建 “Provider” 時(shí)都會(huì)傳入一個(gè) Create
函數(shù),而這個(gè)函數(shù)里一遍我們會(huì)寫一些需要的業(yè)務(wù)邏輯,比如 counterProvider
里的 ()=> 0
就是初始化時(shí)返回一個(gè) int
為 0 的值株汉,更重要的是決定了 State
的類型筐乳。
如果在上面代碼的基礎(chǔ)上增加了 <int>
就更明顯,事實(shí)上前面我們一直在說(shuō)的 State
就是一個(gè)泛型乔妈,而我們定義 “Provider” 就需要定義這個(gè)泛型 State
的類型蝙云,比如這里的 int
。
回歸到普通 Provider
的調(diào)用路召,我們傳入的 Create
函數(shù)勃刨,其實(shí)就是在 ProviderElementBase
里被調(diào)用執(zhí)行。
如上圖所示股淡,簡(jiǎn)單來(lái)說(shuō)當(dāng) ProviderElementBase
執(zhí)行 “setState” 時(shí)身隐,就會(huì)調(diào)用 Create
函數(shù),從而執(zhí)行獲取到我們定義的泛型 State
唯灵,得到 Result
然后通知并更新 UI贾铝。
?? 這里的 “setState” 也不是 Flutter Framework 里的
setState
,而是 RiverPod 內(nèi)自己首先的一個(gè) “setState” 函數(shù)埠帕,和 Flutter 框架里的State
無(wú)關(guān)垢揩。
所以每個(gè) “Provider” 都會(huì)有自己的 “Element” ,而構(gòu)建 “Provider” 時(shí)是傳入的 Create
函數(shù)會(huì)在 “Element” 內(nèi)通過(guò) setState
調(diào)用執(zhí)行敛瓷。
“Element” 里的 setState
主要是通過(guò)新的 newState 去得到一個(gè) RiverPod 里的 Result
對(duì)象叁巨,然后通過(guò) _notifyListeners
去把得到 Result
更新到 watch
的地方。
Result
的作用主要是通過(guò) Result.data
呐籽、Result.error
锋勺、 map
和 requireState
等去提供執(zhí)行結(jié)果,一般情況下?tīng)顟B(tài)都是通過(guò) requireState
獲取绝淡,具體在 RiverPod 體現(xiàn)為:
我們調(diào)用
read()
時(shí)宙刘,其實(shí)最后都調(diào)用到element.readSelf();
,也就是返回requireState
(其實(shí)一般也就是我們的泛型State
) 牢酵。
是不是有點(diǎn)亂悬包?
簡(jiǎn)單點(diǎn)理解就是:構(gòu)建出 “Provider” 之后, “Element” 里會(huì)執(zhí)行setState(_provider.create(this));
調(diào)用我們傳入的 Create
函數(shù)馍乙,并把 “Element” 自己作為 ref
傳入進(jìn)入布近,所以我們使用的 ref
其實(shí)就是 ProviderElementBase
。
所以 RiverPod 里的起名是有原因的丝格,這里的 “Provider” 和 “Element” 的關(guān)系就很有 Flutter 里
Widget
和Element
的即視感撑瞧。
分步驟來(lái)說(shuō)就是:
- 構(gòu)建 Provider 時(shí)我們傳入了一個(gè)
Create
函數(shù); -
Create
函數(shù)會(huì)被ProviderElementBase
內(nèi)部的setState
所調(diào)用显蝌,得到一個(gè)Reuslt
预伺; -
Reuslt
內(nèi)的requireState
就可以讓我們?cè)谑褂?read()
的時(shí)候,獲取到我們定義的 泛型State
的值。
WidgetRef
前面介紹了那么多酬诀,但還是沒(méi)有說(shuō) StateProvider
怎么和 ProviderScope
關(guān)聯(lián)到一起脏嚷,也就是 “Provider” 怎么和 ProviderContainer
關(guān)聯(lián)到一起,憑什么 ref.read
就可以讀到 State
瞒御?
那么前面代碼里父叙,我們用到的 ConsumerWidget
和 Consumer
都是同個(gè)東西,而這個(gè) ref
就是前面我們一直說(shuō)的 “Element” 肴裙,或者說(shuō)是 ProviderElementBase
趾唱。
在源碼里可以看到, ConsumerWidget
的邏輯主要在 ConsumerStatefulElement
蜻懦, 而ConsumerStatefulElement
繼承了 StatefulElement
甜癞,并實(shí)現(xiàn)了 WidgetRef
接口。
如上代碼就可以看到前面很多熟悉的身影了: ProviderScope
阻肩、ProviderContainer
带欢、 WidgetRef
运授。
首先我們看 ProviderScope.containerOf(this)
烤惊,終于看到我們熟悉的 BuildContext
有沒(méi)有,這個(gè)方法其實(shí)就是以前我們常用的 of(context)
吁朦,但是它被放到了 ConsumerStatefulElement
使用柒室,用于獲取 ProviderScope
往下共享的 ProviderContainer
。
所以我們看到了逗宜,ConsumerWidget
里的 ConsumerStatefulElement
獲取到了 ProviderContainer
雄右,所以 ConsumerStatefulElement
可以調(diào)用到 ProviderContainer
的 read/watch 。
然后回過(guò)頭來(lái)看纺讲,ConsumerStatefulElement
實(shí)現(xiàn)了 WidgetRef
接口擂仍,所以 我們使用的 WidgetRef
就是 ConsumerStatefulElement
本身
也就是 ref.read
就是執(zhí)行 ConsumerStatefulElement
的 read
, 從而執(zhí)行到 ProviderContainer
的 read
熬甚。
所以我們可以總結(jié): BuildContext
是 Element
逢渔, 然后 Element
又實(shí)現(xiàn)了 WidgetRef
,所以此時(shí)的 WidgetRef
就是 BuildContext
的替代乡括。
這里不要把 Flutter 的
Element
和 RiverPod 里的 “ProviderElementBase
” 搞混了肃廓。
所以 WidgetRef
這個(gè)接口成為了 Element
的抽象,替代了 BuildContext
诲泌,所以這就是 Riverpod 的“魔法”之一 盲赊。
read
所以前面我們已經(jīng)理清了 ProviderScope
、 Provider
敷扫、 ProviderElementBase
哀蘑、 ProviderContainer
、 ConsumerWidget
(ConsumerStatefulElement
) 和 WidgetRef
等的關(guān)系和功能,那最后我們就可以開(kāi)始理清楚 read
的整個(gè)工作鏈條绘迁。
我們理清和知道了 的概念與作用之后惨险,結(jié)合 ref.read
來(lái)做一個(gè)流程分析,那整體就是:
-
ConsumerWidget
會(huì)通過(guò)內(nèi)部的ConsumerStatefulElement
獲取到頂層ProviderScope
內(nèi)共享的ProviderContainer
脊髓; - 當(dāng)我們通過(guò)
ref
調(diào)用read
/watch
時(shí)辫愉,其實(shí)就是通過(guò)ConsumerStatefulElement
去調(diào)用ProviderContainer
內(nèi)的read
函數(shù);
那最后就是 ProviderContainer
內(nèi)的 read
函數(shù)如何讀取到 State
将硝?
這就要結(jié)合前面我們同樣介紹過(guò)的 ProviderElementBase
恭朗, 事實(shí)上 ProviderContainer
在執(zhí)行 read
函數(shù)時(shí)會(huì)調(diào)用 readProviderElement
。
readProviderElement
顧名思義就是通過(guò) Provider
去獲取到對(duì)應(yīng)的 Element
依疼,例如 :
ref.read(counterProvider),
一般情況下 read/watch 簡(jiǎn)單來(lái)說(shuō)就是從 ProviderContainer
里用 proivder
做 key 獲取得到 ProviderElementBase
這個(gè) “Element”痰腮,這個(gè)過(guò)程又有一個(gè)新的對(duì)象需要簡(jiǎn)單介紹下,就是:_StateReader
律罢。
readProviderElement
其中一個(gè)關(guān)鍵就是獲取 _StateReader
膀值,在 ProviderContainer
里有一個(gè) _stateReaders
的內(nèi)部變量,它就是用于緩存 _StateReader
的 Map 误辑。
所以在 ProviderContainer
內(nèi)部:
- 1沧踏、首先會(huì)根據(jù)
read
時(shí)傳入的provider
構(gòu)建得到一個(gè)_StateReader
; - 2巾钉、以
provider
為 key 翘狱,_StateReader
為 value 存入_stateReaders
這個(gè) Map,并返回_StateReader
砰苍; - 3潦匈、通過(guò)
_StateReader
的getElement()
獲取或者創(chuàng)建到ProviderElementBase
;
這里的以
ProviderBase
為 Key 赚导,_StateReader
為 value 存入_stateReaders
茬缩,其實(shí)就是把 “provider” 存入到了ProviderContainer
,也就是和ProviderScope
關(guān)聯(lián)起來(lái)吼旧,也就是自此 “provider” 和ProviderScope
就綁定到一起凰锡。
沒(méi)用使用到明面上的 BuildContext
和多余的嵌套,就讓 Provider
和 ProviderScope
關(guān)聯(lián)起來(lái)黍少。 另外這里可以看到寡夹,在 ref.read
時(shí),如何通過(guò) provider
構(gòu)建或者獲取到 ProviderElementBase
厂置。
得到 ProviderElementBase
還記得前面我們介紹 “Provider” 和 "Element" 的部分嗎菩掏?ProviderElementBase
會(huì)調(diào)用 setState
來(lái)執(zhí)行我們傳入的 Create
函數(shù),得到 Result
返回 State
昵济。
可以看到智绸,這里獲取的 ProviderElementBase
之后 return element.readSelf()
野揪,其實(shí)就是返回了 requireState
。
自從整個(gè) RiverPod 里最簡(jiǎn)單的 ref.read
流程就全線貫通了:
ProviderScope
往下共享ProviderContainer
瞧栗;ConsumerWidget
內(nèi)部的ConsumerStatefulElement
通過(guò)BuildContext
讀取到ProviderContainer
斯稳, 并且實(shí)現(xiàn)WidgetRef
接口;通過(guò)
WidgetRef
接口的read(provider)
調(diào)用到ProviderContainer
里的read
迹恐;ProviderContainer
通過(guò)read
方法的provider
創(chuàng)建或者獲取得到ProviderElementBase
ProviderElementBase
會(huì)執(zhí)行provider
里的Create
函數(shù)挣惰,來(lái)得到Result
返回State
;
其他的watch
殴边,refresh
流程大同小異憎茂,就是一些具體內(nèi)部實(shí)現(xiàn)邏輯更復(fù)雜而已,比如刷新時(shí):
通過(guò)
ref.refresh
方法锤岸, 其實(shí)觸發(fā)的就是ProviderContainer
的refresh
竖幔,然后最終還是會(huì)通過(guò)_buildState
去觸發(fā)setState(_provider.create(this))
的執(zhí)行。
而從這個(gè)流程分析是偷,也看到了 RiverPod 如何不暴露使用 BuildContext
實(shí)現(xiàn)全線關(guān)聯(lián)的邏輯拳氢。
額外分析
前面基本介紹完整個(gè)調(diào)用流程,這里在額外介紹一些常見(jiàn)的調(diào)用時(shí)如何實(shí)現(xiàn)蛋铆,比如在 Riverpod 里面會(huì)看到很多 “Element” 馋评,比如 ProviderElement
、StreamProviderElement
戒职、 FutureProviderElement
等這些 ProviderElementBase
的子類栗恩。
我們結(jié)果過(guò)它們并不是 Flutter 里的 Element
禽炬,而是 Riverpod 里的的 State 單位步淹,用于處理 Provider
的狀態(tài)轻姿,比如 FutureProviderElement
就是在 ProviderElementBase
的基礎(chǔ)上提供一個(gè) AsyncValue<State>
,主要在 FutureProvider
里使用捧韵。
AsyncValue
在 RiverPod 里正常情況下的 create 方法定義是如下所示:
而在 FutureProvider
下是多了一個(gè) _listenFuture
,這個(gè) Function 執(zhí)行后的 value
就會(huì)是 AsyncValue<State>
的 State 類型汉操。
從 _listenFuture
的執(zhí)行上看再来, 內(nèi)部會(huì)對(duì)這個(gè) future()
執(zhí)行,會(huì)先進(jìn)入 AsyncValue<State>.loading()
之后磷瘤,根據(jù) Future
的結(jié)果返回決定返回AsyncValue<State>.data
或者 AsyncValue<State>.error
芒篷。
所以比如在 read
/ watch
時(shí),返回的泛型 requireState
其實(shí)變成了 AsyncValue<State>
采缚。
而針對(duì) AsyncValue
官方做了一些 extension
针炉,在 AsyncValueX
上,其中出了獲取 AsyncData
的data
\ asData
和 T value 之外扳抽,最主要提供了起那么所說(shuō)的不同狀態(tài)的構(gòu)建方法篡帕,比如 when
方法:
autoDispose & family
在 Riverpod 里應(yīng)該還很常見(jiàn)一個(gè)叫 autoDispose
和 family
的靜態(tài)變量殖侵,幾乎每個(gè) Provider
都有,又是用來(lái)干什么的呢镰烧?
舉個(gè)例子拢军,前面代碼里我們有個(gè) FutureProvider
, 我們用到了里的 autoDispose
:
其實(shí) FutureProvider.autoDispose
主要就是 AutoDisposeFutureProvider
怔鳖,以此類推基本每個(gè) Provider
都有自己的 autoDispose
實(shí)現(xiàn)茉唉,family
也是同理。
如果說(shuō)正常的 Provider
是繼承了 AlwaysAliveProviderBase
结执,那 AutoDisposeProvider
就是繼承于 AutoDisposeProviderBase
:
從名字可以看出來(lái):
-
AlwaysAliveProviderBase
是一只活躍的赌渣; -
AutoDisposeProviderBase
自然就是不listened
的時(shí)候就銷毀;
也就是內(nèi)部 _listeners
昌犹、_subscribers
坚芜、_dependents
都是空的時(shí)候,當(dāng)然它還有另外一個(gè) maintainState
的控制狀態(tài)斜姥,默認(rèn)它就是 false
的時(shí)候鸿竖,就可以執(zhí)行銷毀。
簡(jiǎn)單理解就是用“完即焚燒” 铸敏。
比如前面我們介紹調(diào)用 read
的時(shí)候缚忧,都會(huì)調(diào)用 mayNeedDispose
去嘗試銷毀:
銷毀也就是調(diào)用
element.dispose()
和從_stateReaders
這個(gè)map
里移除等等。
同樣的 family
對(duì)應(yīng)是 ProviderFamily
杈笔,它的作用是:使用額外的參數(shù)構(gòu)建 provider 闪水,也即是增加一個(gè)參數(shù)。
例如默認(rèn)是把 :
final tagThemeProvider = Provider<TagTheme>
可以變成
final tagThemeProvider2 = Provider.family<TagTheme, Color>
然后你就可以使用額外的參數(shù)蒙具,在 read
/watch
的時(shí)候 :
final questionsCountProvider = Provider.autoDispose((ref) {
return ref
.watch(tagThemeProvider2(Colors.red));
});
之所以可以實(shí)現(xiàn)這個(gè)功能球榆,就要看它的實(shí)現(xiàn) ProviderFamily
,對(duì)比一般 Provider
默認(rèn)的 create
禁筏,ProviderFamily
的是:
可以看到 create
的是新的一個(gè) Provider
持钉,也就是 family
下其實(shí)是 Provider
嵌套 Provider
。
所以從上面的例子出發(fā)篱昔,以前我們是通過(guò) ref.watch(tagThemeProvider);
就可以了每强,因?yàn)槲覀兊?tagThemeProvider
的直接就是 ProviderBase
。
但是如果使用 ref.watch(tagThemeProvider2);
就會(huì)看到錯(cuò)誤提示
The argument type 'ProviderFamily<TagTheme, Color>' can't be assigned to the parameter type 'ProviderListenable<dynamic>'.
是的州刽,因?yàn)檫@里是 Provider
嵌套 Provider
空执,我們先得到是的 ProviderFamily<TagTheme, Color>
,所以我們需要改為 ref.watch(tagThemeProvider2(Colors.red));
穗椅。
通過(guò) tagThemeProvider2(Colors.red)
執(zhí)行一次變?yōu)槲覀冃枰?ProviderBase
辨绊。
那 tagThemeProvider2
這個(gè) ProviderFamily
為什么是這樣執(zhí)行? ProviderFamily
明明沒(méi)有這樣的構(gòu)造函數(shù)房待。
這就涉及到 Dart 語(yǔ)言的特性邢羔,如果有興趣可以看 : juejin.cn/post/696836…
首先這里拿到的是一個(gè) ProviderFamily<TagTheme, Color>
驼抹,在 Dart 中所有函數(shù)類型都是 Function
的子類型,所以函數(shù)都固有地具有 call
方法拜鹤。
我們執(zhí)行 tagThemeProvider2(Colors.red)
其實(shí)就是執(zhí)行了 ProviderFamily
得 call
方法框冀,從而執(zhí)行了 create
方法,得到 FamilyProvider<State>
敏簿,FamilyProvider
也就是 ProviderBase
的子類 明也。
??注意這里有點(diǎn)容易看錯(cuò)的地方,一個(gè)是
ProviderFamily
惯裕, 一個(gè)是FamilyProvider
温数, 我們從ProviderFamily
里面得到了FamilyProvider
, 作為ProviderBase
給ref.watch
蜻势。
最后
很久沒(méi)有寫這么長(zhǎng)的源碼分析了撑刺,不知不覺(jué)就寫到了半夜凌晨,其實(shí)相對(duì)來(lái)說(shuō)握玛,整個(gè) Riverpod 更加復(fù)雜够傍,所以閱讀起來(lái)也更加麻煩,但是使用起來(lái)反而會(huì)相對(duì)更便捷挠铲,特別是沒(méi)有了 BuildContext
的限制冕屯,但是同時(shí)也是帶來(lái)了 ConsumerWidget
的依賴,所有利弊只能看你自己的需求拂苹,但是整體 Riverpod 肯定是一個(gè)優(yōu)秀的框架安聘,值得一試。