Как правильно использовать провайдера во флаттере - PullRequest
0 голосов
/ 19 февраля 2020

Итак, у меня есть этот ChangeNotifierProvider высоко в моем дереве виджетов, так как я вижу много дочерних виджетов, которые слушают его значение.

В настоящее время я делаю, что я передаю Provider.of ( context) объект из родительского виджета в его потомки через конструкторы всякий раз, когда мне нужно повторно использовать некоторые значения / функции в моих дочерних виджетах. Например, каждый раз, когда я создаю объект Provider.of (context) для своих дочерних виджетов, создается впечатление, что он не переносит обновленные значения, которые есть в Parent Provider, а имеет значение по умолчанию null. / 0 / 'пустые', как будто они только созданы. Это заставило меня передать начальный Provider.of (context) каждому дочернему элементу, который будет использовать обновленные значения и функции ChangeNotifier.

Эта настройка работает для меня, однако Когда мое дерево виджетов стало сложным, я постоянно передаю значения через каждый виджет и некоторым, которые вообще не используют его только для того, чтобы его дети слушали основного поставщика.

Я думаю, что Возможно, я сейчас занимаюсь анти-паттерном архитектуры провайдеров, надеюсь, вы, ребята, сможете помочь мне в более оптимизированном и эффективном способе сделать это.

Большое спасибо!

PS В документации есть некоторые вещи, которые я еще не совсем правильно понял.

Правки Ниже приведены примеры кода и визуализация:

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}'
        );
    }
}

scre ru_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}'
            )
        ]
        );
    }
}

Визуализация

enter image description here

То, что я сейчас делаю, - это передать объект providerType из ScreenColumn на экраны A, B и C, чтобы каждый из них имеют тот же «Источник ценностей». Потому что, когда я пытаюсь создать разные объекты Provider.of и использовать их, они не используют одни и те же обновленные значения, когда я выполняю некоторые вычисления.

Есть ли что-то, что я могу сделать, чтобы сделать это более эффективным, или есть лучший способ, что мне нужно сделать?

1 Ответ

0 голосов
/ 20 февраля 2020

Для тех, кто может задаться вопросом или ищет ответы на тот же вопрос, посмотрите на мой пример кода ниже, который показывает, как вы можете повторно использовать / делиться значениями и функциями вашего провайдера в любой точке дерева виджетов, если они есть. под вашим родительским провайдером.

И да, вы можете просто создать объекты Provider.of в любом месте вашего дерева, не передавая исходный объект Provider.of, который вы создали.

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),
          ],
        ),
      ),
    );
  }
}
...