Flutter中各種Consumer的區(qū)別和使用場景

在項目中,遇到了各種Consumer,剛開始的時候還不知道他們有什么區(qū)別,后面通過一些開發(fā)實踐逐漸摸清楚了他們之間的區(qū)別和使用場景。
首先,這些Consumer來源于riverpod這個庫,主要是提升開發(fā)者對provider的使用,便于獲取provider,實現(xiàn)相關(guān)的狀態(tài)管理。

1. ConsumerWidget

是一個StatefulWidget,但是不需要我們?nèi)崿F(xiàn)相關(guān)的Widget和State。內(nèi)部已經(jīng)幫我們封裝實現(xiàn)好了。使用時,只要繼承ConsumerWidget,實現(xiàn)Widget build(BuildContext context, WidgetRef ref);函數(shù)即可。然后通過ref獲取需要的provider

2. Consumer

是對ConsumerWidget的進一步封裝。對于一些Widget我們不想去新建一個類來繼承ConsumerWidget,那我們可以使用Consumer來包裹Widget。
例子:

Consumer(
    builder: (context, ref, child) {
        final value = ref.watch(helloWorldProvider);
        return Text(value);
    },
);

3. HookConsumerWidget

HookConsumerWidget是HookWidget和ConsumerWidget的結(jié)合。HookWidget的主要作用是在封裝好的StateLessWidget,實現(xiàn)一些需要initState或者dispose回調(diào)的一些方法,比如AnimationController或者是做一些緩存。
而ConsumerWidget雖然是StatefulWidget,但是沒辦法回調(diào)initState和dispose,所以通過將HookConsumerWidget,就可以在使用Consumer的時候,實現(xiàn)一些需要initState和dispose的邏輯。

@override
Widget build(BuildContext context, WidgetRef ref) {
  // 初始化一個變量,并且只會執(zhí)行一次
  final count = useState<T>(initValue);
  // 改變變量的值,并且會刷新widget,相當于setState
  count.value++;

  useEffect({
    // 做一些initState的操作
    // 這里的執(zhí)行只有Widget第一次build的時候才會執(zhí)行
    return method.call();// 這個方法在widget dispose的時候會執(zhí)行。
  })

  // 一條語句可以實現(xiàn)animationController的初始化和自動dispose
  final animationCtrl =
        useAnimationController(duration: 300.milliseconds, initialValue: 0);
}

更多Hook用法參考:Hook的用法

4. HookConsumer

HookConsumer就是對HookConsumerWidget的進一步封裝,對于一些不需要新建一個類去繼承HookConsumerWidget的,那就直接用HookConsumer。就如同Consumer和ConsumerWidget之間的關(guān)系一樣。

5. RiverpodConsumer

是內(nèi)部自己實現(xiàn)的一個HookConsumer,傳入listenable和builder可以實現(xiàn)provider的監(jiān)聽和rebuild。對于只需要監(jiān)聽單一變量時,使用RiverpodConsumer是比較方便的,但是如果一個widget需要監(jiān)聽多個變量,對這些變量做出對應(yīng)的widget更新,那是不建議使用RiverpodConsumer進行多層嵌套的。因為RiverpodConsumer實際內(nèi)部還是用Consumer實現(xiàn)的,而Consumer實際是一個StatefulWidget,所以RiverpodConsumer的嵌套實際上就是StatefulWidget的嵌套,這個是損耗性能并且是沒必要的操作。還降低了代碼的可讀性。

6. WidgetRef的監(jiān)聽

WidgetRef中一共有4種調(diào)用provider的方式,分別是read, listen, watch和refresh,其中前3種比較常見和易用。read是獲取provider的當前狀態(tài),如果后續(xù)provider發(fā)生改變了,那么獲得的值并不會更新。并且,當provider是AutoDispose的,那么在read完這個provider之后,provider就會被dispose,即使當前頁面沒有銷毀,provider也同樣會被dispose。
而listen和watch是可以監(jiān)聽provider的變化。他們的區(qū)別是,listen是監(jiān)聽provider的變化,然后在回調(diào)函數(shù)中做對應(yīng)的邏輯處理。而watch是監(jiān)聽provider的變化,然后讓·ref對應(yīng)的widget自動重建。
所以,當我們使用watch的時候應(yīng)該盡可能的讓底層的ref去做監(jiān)聽,來避免大量widget的重建。并且監(jiān)聽的時候盡量使用provider.select((value) => value.member)監(jiān)聽provider中的某個變量的變化。來避免provider其他不相關(guān)的變量發(fā)生變化引起不必要的重建。
另外,當我們監(jiān)聽provider中的集合時,如果是集合中的元素發(fā)生變化(增刪改),通過provider.select((value) => value.collection)是沒辦法監(jiān)聽到的,此時只能ref.watch(provider)監(jiān)聽整個provider來獲取集合元素的變化。除非是在集合元素發(fā)生變化后,重新對集合進行賦值,那就可以監(jiān)聽select。
對provider中的對象同理。如果是修改對象的某個成員變量,只監(jiān)聽該對象是無法獲得該對象的某個成員變量的變化。需要監(jiān)聽該對象的成員變量。

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

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

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