Flutter Provider

InheritedWidget 組件是功能型組件,提供了沿樹向下,共享數(shù)據(jù)的功能,即子組件可以獲取父組件(InheritedWidget 的子類)的數(shù)據(jù),通過BuildContext.dependOnInheritedWidgetOfExactType 獲取。

class MyInheritedWidget extends InheritedWidget {
  final UserInfo userInfo;

  MyInheritedWidget({this.userInfo, Widget child}):super(child: child);

  static MyInheritedWidget of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }

  @override
  bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {
    return oldWidget.userInfo != userInfo;
  }
}

updateShouldNotify 方法必須重寫,此方法是判斷新的共享數(shù)據(jù)和原數(shù)據(jù)是否一致,是否將通知傳遞給所有子組件(已注冊)。重建此組件時,有時需要重建繼承 InheritedWidget 組件的組件,但有時不需要。 例如,如果此組件所保存的數(shù)據(jù)與“ oldWidget”所保存的數(shù)據(jù)相同,則我們無需重建繼承了“ oldWidget”所保存的數(shù)據(jù)的組件。

class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {
  UserInfo _userInfo = UserInfo(name: 'lisa', age: 18);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('InheritedWidget Demo'),
      ),
      body: Center(
        child: MyInheritedWidget(
          userInfo: _userInfo,
          child: A(
            child: F(),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _userInfo = UserInfo(name: '小明', age: 18);
          });
        },
      ),
    );
  }
}

下面是A和F

class F extends StatefulWidget {
  @override
  _FState createState() => _FState();
}
class _FState extends State<F> {
  @override
  void initState() {
    super.initState();
    print('F initState');
  }
  @override
  Widget build(BuildContext context) {
    print('F build');
    return Text('name:${MyInheritedWidget.of(context).userInfo.name}');
  }
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('F didChangeDependencies');
  }
}

class A extends StatefulWidget {
  final Widget child;
  const A({Key key, this.child}) : super(key: key);
  @override
  _AState createState() => _AState();
}

class _AState extends State<A> {
  @override
  void initState() {
    super.initState();
    print('A initState');
  }

  @override
  Widget build(BuildContext context) {
    print('A build');
    return Center(
      child: widget.child,
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('A didChangeDependencies');
  }
 
}

修改_userInfo時依賴 MyInheritedWidget 組件的 F 組件調用 didChangeDependencies 方法,而 A 組件沒有調用 didChangeDependencies 方法,因為 A 沒有依賴 MyInheritedWidget 組件。

F 組件使用 InheritedWidget 的共享數(shù)據(jù)并展示,如果 updateShouldNotify 返回 false,那么 F 組件 rebuild 時只會執(zhí)行 build 函數(shù),而 updateShouldNotify 返回 true時, F 組件 rebuild 時會執(zhí)行 didChangeDependencies 和 build 函數(shù),因此可以將類似訪問服務器接口這種耗時工作放在 didChangeDependencies 函數(shù)中,這也是 didChangeDependencies 生命周期存在的意義。

使用方法

Step1:添加依賴
dependencies:
  flutter:
    sdk: flutter
   provider: ^4.0.4
Step:創(chuàng)建一個ChangeNotifier

我們先新建一個 NumberManager,繼承 ChangeNotifier,使之成為我們的數(shù)據(jù)提供者之一。

class NumberManager with ChangeNotifier, DiagnosticableTreeMixin {
  int _firstNum = 0;
  int _secondNum = 0;

  int get firstNum => _firstNum;
  int get secondNum => _secondNum;

  void changeData1() {
    _firstNum++;
    notifyListeners();
  }

  void changeData2() {
    _secondNum++;
    notifyListeners();
  }
}
Step5:創(chuàng)建ChangeNotifierProvider
List<SingleChildWidget> providerList = [
   ChangeNotifierProvider(create: (context) => NumberManager()),
];

void main() {
  // ignore: prefer_const_constructors
  runApp(MultiProvider(
    providers: providerList,
    child: MyApp(),
  ));
  // runApp(const MyApp());
}

獲取數(shù)據(jù)

1. 使用Provider.of<T>(context)方法來引用數(shù)據(jù)

  • read讀取數(shù)據(jù),如果數(shù)據(jù),不會主動調用build,所以數(shù)據(jù)變化后,顯示的數(shù)據(jù)再沒有重新build前,顯示的還是之前的數(shù)據(jù):
context.read()
 T read<T>() {
    return Provider.of<T>(this, listen: false);
  }
  • Provider.of<T>(context) 可以簡寫為context.watch(),
context.watch()
T watch<T>() {
   return Provider.of<T>(this);
 }
}

通過此方法應用數(shù)據(jù)時,當前widget所在的build會在收到通知時進行重繪,所以在使用過程中如果不希望當前widget所在的類進行rebuild,可以為當前widget單獨創(chuàng)建一個StatelessWidget:

class FirstNumWidget extends StatelessWidget {
  const FirstNumWidget({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    print("----------FirstNumWidget被重執(zhí)行了----------");

    //  使用Provider.of<T>(context)方法來引用數(shù)據(jù),每次數(shù)據(jù)變化都會重新build
    return ElevatedButton(
      child: Text(
          "consumer firstNum的值:${Provider.of<NumberManager>(context).firstNum}"),
      onPressed: () {
        Provider.of<NumberManager>(context, listen: false).changeData1();
      },
    );
  }
}

Consumer

具體用法如下,builder 中的參數(shù)分別是 Context context, T value, Widget child,value 即Model1,value 的類型和 Model1 類型一致,builder 方法返回的是 Widget,也就是被 Consumer 包裹的 widget,當監(jiān)聽的 model 值發(fā)生改變,此 widget 會被 Rebuild。

Consumer<Model>(
        builder: (context, model, child) {
          return Text('Model count:${model.count}');
        },
 )

Selector

Selectord定義

class Selector<A, S> extends Selector0<S> {
    Key key,
    //  Widget Function(BuildContext context, T value, Widget child)
    // 用于構建 Widget
    @required ValueWidgetBuilder<S> builder,
    // S Function(BuildContext, A)
    // 用于指定使用哪個值作為重重建判斷依據(jù)
    @required S Function(BuildContext, A) selector,
    // bool Function(T previous, T next)
    // 是否重建,一般情況下不用我們實現(xiàn)
    ShouldRebuild<S> shouldRebuild,
    Widget child,
  })

Selector 和 Consumer 很相似,唯一不同的是,Selector 可以自定義返回類型 ,所以Selector可以自定義是否在收到通知時進行頁面重繪

Selector<Model1, int>(
 builder: (context, count, child) => Text(
   "Selector示例演示: $count",
   style: Theme.of(context).textTheme.title,
 ),
 selector: (context, model) => model.count,
),

Selector 有 Selector0 ~ Selector6,具體使用大同小異,可以傳 0 ~ 6 個 ChangeNotifer,但是 S(Value)泛型只有一個,如果需要多個個值同時判斷返回 S 怎么辦呢?這個時候可以使用元祖 Tuple

總結

Consumer 可以避免 widget 多余的 rebuild,當 Consumer 中監(jiān)聽的 value 不發(fā)生變化,其包裹的 widget 不會 Rebuild。 Selector 在 Consumer 基礎上提供了更加精確的監(jiān)聽,還支持自定義 rebuild,可以更加靈活地控制 widget rebuild 問題。

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容