如何在 Flutter 中正确复用 Provider

How to properly reuse a Provider in Flutter

所以我的小部件树中有这个 ChangeNotifierProvider,因为我看到很多 children 小部件来监听它的值。

我目前正在做的是将 Provider.of(context) object 从 parent 小部件传递到它的 children 每当我要在我的 children 小部件上重用一些 values/functions 时通过构造函数。例如,每次我为 children 小部件创建 Provider.of(context) object 时,它似乎不会继承更新的值我有 Parent 提供商,但这个提供商有我的默认 null/0/'empty' 就像它只是被创建的一样。这导致我将初始 Provider.of(context) object 传递给每个将使用 ChangeNotifier 的更新值和函数的 children。

这个设置对我有用,但是,当我的小部件树开始变得复杂时,我不断地通过每个小部件和一些甚至根本不使用它的小部件传递值,只是为了它的 children 收听主要提供者。

我想我现在可能正在做的是anti-pattern Provider Architecture,我希望你们能帮助我以一种更优化和更有效的方式来做这件事。

非常感谢!

P.S。文档中有些东西我还没有完全掌握。

编辑以下以包含示例代码和可视化:

provider_type.dart

class ProviderType extends ChangeNotifier{
    String valueA = '';
    String valueB = '';
}

home.dart

import ..provider_type.dart
...
    Widget build(BuildContext context){
        return ChangeNotifierProvider<ProviderType>(
            create: (context) => ProviderType(),
            child: ScreenColumn();
        );
    }
...

screen_column.dart

import ..screen_a.dart
import ..screen_b.dart
class ScreenColumn extends StatelessWidget{
    Widget build(BuildContext context){
        var providerType = Provider.of<ProviderType>(context);

        return Column(
            children: <Widget>[
                ScreenA(providerType: providerType),
                ScreenB(providerType: providerType),
            ],
        );
    }
}

screen_a.dart

class ScreenA extends StatelessWidget{
    final ProviderType providerType;

    ScreenA({this.providerType});

    Widget build(BuildContext context){
        return Text(
            '${providerType.valueA}'
        );
    }
}

screen_b.dart

import ..screen_c.dart
class ScreenB extends StatelessWidget{
    final ProviderType providerType;

    ScreenB({this.providerType});

    Widget build(BuildContext context){
        return ScreenC(providerType: providerType);
    }
}

screen_c.dart

class ScreenC extends StatelessWidget{
    final ProviderType providerType;

    ScreenB({this.providerType});

    Widget build(BuildContext context){
        return Column(
        children: <Widget>[
            Text(
                '${providerType.valueA}'
            )
            Text(
                '${providerType.valueB}'
            )
            Text(
                '${providerType.valueC}'
            )
        ]
        );
    }
}

可视化

所以我目前正在做的是将 object providerType 从 ScreenColumn 传递给屏幕 A、B 和 C,这样它们每个都具有相同的"Source of Values"。因为当我尝试制作不同的 Provider.of object 并使用它们时,当我进行一些计算时它们不会共享相同的更新值。

我可以做些什么来提高效率还是我需要做的更好的方法?

对于那些可能想知道或正在寻找同一问题的答案的人,请查看我下面的示例代码,它显示了如何 reuse/share 您的提供程序值和功能在您的小部件树中的任何点作为只要它们在您的 Parent 供应商之下。

And yes, you can actually just create Provider.of Objects anywhere in your tree without passing down the initial Provider.of object that you have created.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ProviderType extends ChangeNotifier {
  String value = DateTime.now().toString();

  changeValue() {
    value = DateTime.now().toString();
    notifyListeners();
  }
}

void main() => runApp(AppIndex());

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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<ProviderType>(
      create: (context) => ProviderType(),
      child: MaterialApp(
        home: Home(),
      ),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var providerType = Provider.of<ProviderType>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Sample App'),
      ),
      body: ScreenColumn(),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () => providerType.changeValue(),
        label: Text('ChangeValue'),
      ),
    );
  }
}

class ScreenColumn extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
        child: Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        ScreenA(),
        ScreenB(),
        ScreenC(),
        ScreenC(),
      ],
    ));
  }
}

class ScreenA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var providerType = Provider.of<ProviderType>(context);
    return Card(
      color: Colors.red,
      elevation: 8.0,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Text(providerType.value),
      ),
    );
  }
}

class ScreenB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var providerType = Provider.of<ProviderType>(context);
    return Card(
      color: Colors.blue,
      elevation: 8.0,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(providerType.value),
            ScreenC(),
            ScreenC(),
          ],
        ),
      ),
    );
  }
}

class ScreenC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // var providerType = Provider.of<ProviderType>(context);

    return Card(
      color: Colors.green,
      elevation: 8.0,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text('This is Screen B with no Provider.of Object'),
            ScreenD(),
            ScreenD(),
            ScreenD(),
          ],
        ),
      ),
    );
  }
}

class ScreenD extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var providerType = Provider.of<ProviderType>(context);
    return Card(
      color: Colors.yellow,
      elevation: 8.0,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(
                'This is Screen D. A Provider.of object was created here without inheriting the Parent\'s Provider.of object.'),
            Text(providerType.value),
          ],
        ),
      ),
    );
  }
}