Flutter Provider

484 阅读2分钟

Flutter Provider

Provider是官方推荐的全局状态管理工具

安装

dependencies:
  provider: ^4.3.2+2

第一步

import 'package:flutter/material.dart';

// 1.创建自己需要共享的数据
class CounterViewModel extends ChangeNotifier{
  int _counter = 100;

  int get counter => _counter;

  set counter(int value) {
    _counter = value;
    notifyListeners();  // 监听
  }
}
import 'dart:math';

import 'package:HM/store/counter_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

/*
* 1.创建自己需要共享的数据
* 2.在应用程序的顶层创建 ChangeNotifierProvider
* 3.在其他位置使用共享的数据
*   * Provider.of 当Provider中的数据发生改变时,Provider.of所在的Widget整个build方法都会重新构建
*   * Consumer  (推荐) 当Provider中的数据发生改变时,只会执行consumer的builder方法
*     * 在floatingActionButton当中的Icon是最不需要被重新渲染的一个Widget,我们可以将他放入child当中 这样每次修改数据的时候都不会重新build到这个widget
*   * Selector: 1.selector方法 对原有的数据进行转换
*               2.shouldRebuild 要不要重新构建
* */
void main() {
  runApp(
    // 2.在应用程序的顶层创建 ChangeNotifierProvider
    ChangeNotifierProvider(
      create: (ctx) => CounterViewModel(), //create 放共享数据
      child: MyApp(),
    )
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      home: providerContent(),
    );
  }
}

class providerContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("providerTest"),
      ),
      body: ProviderPage(),
      // floatingActionButton: Consumer<CounterViewModel>(
      //   builder: (ctx,counterVM,child){
      //     return FloatingActionButton(
      //       child: child,
      //       onPressed: (){
      //         counterVM.counter += 1;
      //       },
      //     );
      //   },
      //     child:Icon(Icons.add);
      // )
      floatingActionButton: Selector<CounterViewModel,CounterViewModel>(
        selector: (ctx,counterVM) => counterVM, // 对原有的数据进行转换
        shouldRebuild: (prev,next) => false,    // 这里表示需不需要重新构建
        builder: (ctx,counterVM,child){
          return FloatingActionButton(
            child: child,
            onPressed: (){
              counterVM.counter += 1;
            },
          );
        },
          child:Icon(Icons.add)
      ),
    );
  }
}

class ProviderPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ShowData01(),
          ShowData02(),
        ],
      ),
    );
  }
}

class ShowData01 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 3.在其他位置使用共享的数据
    int counter = Provider.of<CounterViewModel>(context).counter;
    return Container(
      color: Colors.lime,
      child: Text("当前计数$counter",style: TextStyle(fontSize: 30),),
    );
  }
}

class ShowData02 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 3.在其他位置使用共享的数据
    int counter = Provider.of<CounterViewModel>(context).counter;
    return Container(
      color: Colors.pinkAccent,
      child: Consumer<CounterViewModel>(
        builder: (ctx,counterVM,child){
          return Text("当前计数${counterVM.counter}",style: TextStyle(fontSize: 30),);
        },
      ),
    );
  }
}

Provider.of

Consumer

Selector

当我们数据发送改变的时候,我们不希望floatingActionButton 这个按钮重新 builder

当我们需要有多个状态 model 需要共享的时候我们可以使用 MultiProvider

void main() {
  runApp(
    // 使用多个状态model
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (ctx) => CounterViewModel(),),
        ChangeNotifierProvider(create: (ctx) => UserViewModel(UserInfo("Penny",20,"url")),)
      ],
      child: MyApp(),
    )
  );
}

Consumer2

class ShowData03 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer2<UserViewModel,CounterViewModel>( // Consumer2 可以使用两种state状态数据
      builder: (ctx,userVM,counterVM,child){
        return Text(
          "nickName:${userVM.user.nickname} counter:${counterVM.counter}",
          style: TextStyle(fontSize: 20),
        );
      },
    );
  }
}

这样就能拿到两种不同model的数据了