[Flutter] Provider Essential - 2


MultiProvider
複数のProviderを使用する場合は、複数のProviderを使用できます.
MultiProvider(
	providers: [
    	ChangeNotifierProvider<T>(
          create: (context) => T(),
        ),
        ChangeNotifierProvider<S>(
          create: (context) => S(),
        ),
        ChangeNotifierProvider<R>(
          create: (context) => R(),
        ),
      ],
      child: MaterialApp(
        title: 'Provider',
        home: const MyHomePage(),
      ),
    );
Consumer
これは建設者を利用する方法です.新しい部品でプログラムを提供します.の呼び出しと構築をbuilderに委任します.
class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Consumer<Dog>(
        builder: (BuildContext context, Dog dog, Widget? child) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text('- name:${dog.name}'),
              ],
            ),
          );
        },
      ),
    );
  }
}
Column内で再構築を必要としない部品を再構築すると、効率が低下します.この場合builderのchildパラメータを使用します.
class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Consumer<Dog>(
        builder: (BuildContext context, Dog dog, Widget? child) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                child!,
                Text('- name: ${dog.name}'),
              ],
            ),
          );
        },
        child: Text(
          'This is Child',
          style: TextStyle(fontSize: 20.0),
        ),
      ),
    );
  }
}
ProviderNotFoundException
class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: ChangeNotifierProvider<Foo>(
        create: (_) => Foo(),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('${context.watch<Foo>().value}'),
              ElevatedButton(
                onPressed: () => context.read<Foo>().changeValue(),
                child: Text('Change Value'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
上記のサンプルコードを作成して再起動すると、次のエラーが発生します.
  • You used a BuildContext that is an ancestor of the provider you are trying to read.
    Make sure that MyHomePage is under your MultiProvider/Provider.
    This usually happens when you are creating a provider and trying to read it immediately.
    For example, instead of:
  •   Widget build(BuildContext context) {
        return Provider<Example>(
          create: (_) => Example(),
          // Will throw a ProviderNotFoundError, because `context` is associated
          // to the widget that is the parent of `Provider<Example>`
          child: Text(context.watch<Example>()),
        ),
      }
    consider using builder like so:
    Widget build(BuildContext context) {
      return Provider<Example>(
        create: (_) => Example(),
        // we use `builder` to obtain a new `BuildContext` that has access to the provider
        builder: (context) {
          // No longer throws
          return Text(context.watch<Example>()),
        }
      ),
    }
    エラーメッセージはbuliderを使用してcontextを取得することを示します.
    builderはBuildContextを提供する役割を果たしています.次のコードのようにbuliderを追加してエラーを解決できます.
    class MyHomePage extends StatelessWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          body: ChangeNotifierProvider<Foo>(
            create: (_) => Foo(),
            child: Builder(builder: (BuildContext context) {
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text('${context.watch<Foo>().value}'),
                    ElevatedButton(
                      onPressed: () => context.read<Foo>().changeValue(),
                      child: Text('Change Value'),
                    ),
                  ],
                ),
              );
            }),
          ),
        );
      }
    }
    Consumerで解決することもできます.
    class MyHomePage extends StatelessWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          body: ChangeNotifierProvider<Foo>(
            create: (_) => Foo(),
            child:
                Consumer<Foo>(builder: (BuildContext context, Foo foo, Widget? _) {
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text('${foo.value}'),
                    ElevatedButton(
                      onPressed: () => foo.changeValue(),
                      child: Text('Change Value'),
                    ),
                  ],
                ),
              );
            }),
          ),
        );
      }
    }
    Selector
    Consumerと差が少ないので、動作はもっと丁寧にしなければなりません.
    複数のpropertyを持つobjectタイプと、選択するpropertyタイプの2つのタイプを指定します.
    次に、selector callbackは、リスニングしたいプロパティを返します.builder callbackは、2番目のパラメータセレクタの2番目のタイプのパラメータを指定します.
    class Home extends StatelessWidget {
      const Home({Key? key}) : super(key: key);
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          body: Selector<Dog, String>(
            selector: (BuildContext context, Dog dog) => dog.name,
            builder: (BuildContext context, String name, Widget? child) {
              return Column(
                children: [
                  child!,
                  Text('- name: $name'),
                ],
              );
            },
            child: Text('I like dogs very much'),
          ),
        );
      }
    }
    Reference
    Heavy Fran - Flutter Provider Essential