【问题标题】:How to properly initialize a Future in Flutter Provider如何在 Flutter Provider 中正确初始化 Future
【发布时间】:2020-06-12 04:09:29
【问题描述】:

所以我正在尝试通过 Future Call 在我的提供者中建立一个列表。

到目前为止,我在下面有以下 ChangeNotifier 类:

class MainProvider extends ChangeNotifier {
  List<dynamic> _list = <dynamic>[];
  List<dynamic> get list => _list;
  int count = 0;

  MainProvider() {
    initList();
  }

  initList() async {
    var db = new DatabaseHelper();

    addToList(Consumer<MainProvider>(
        builder: (_, provider, __) => Text(provider.count.toString())));

    await db.readFromDatabase(1).then((result) {
      result.forEach((item) {
        ModeItem _modelItem= ModeItem.map(item);

        addToList(_modelItem);
      });
    });
  }

  addToList(Object object) {
    _list.add(object);
    notifyListeners();
  }

  addCount() {
    count += 1;
    notifyListeners();
  }
}

但是,每当我使用 list 值时,都会发生这种情况:

  1. 我可以确认我的 initList 函数正在正确执行
  2. list 值中可用的初始内容是 我首先通过addToList函数插入的Text()小部件,这意味着此时列表中似乎只有一项
  3. 当我执行热重载时,列表的其余内容现在似乎出现了

注意事项:

  1. 我在 AnimatedList 小部件中使用 list 的值,所以我是 应该显示 list 的内容
  2. 最初出现的是我的list值的内容只有一项
  3. 我的 list 值似乎不会在 执行我的 Future 调用
  4. 但是,当我尝试调用 addCount 函数时,它正常 更新 count 的值而不需要执行 Hot Reload - 这个似乎运行正常
  5. Future 调用似乎没有正确更新 我的列表值的内容

我真正担心的是,在初始加载时,我的列表值不会 按预期正确初始化它的所有值

希望你们能帮助我解决这个问题。谢谢。

更新:下面显示了我如何使用上面的 ChangeNotifierClass

class ParentProvider extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<MainProvider>(
          create: (context) => MainProvider(),
        ),
      ],
      child: ParentWidget(),
    );
  }
}

class ParentWidget extends StatelessWidget {
  final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();

  @override
  Widget build(BuildContext context) {
    var mainProvider = Provider.of<MainProvider>(context);

    buildItem(BuildContext context, int index, Animation animation) {
      print('buildItem');

      var _object = mainProvider.list[index];
      var _widget;

      if (_object is Widget) {
        _widget = _object;
      } else if (_object is ModelItem) {
        _widget = Text(_object.unitNumber.toString());
      }

      return SizeTransition(
        key: ValueKey<int>(index),
        axis: Axis.vertical,
        sizeFactor: animation,
        child: InkWell(
          onTap: () {
            listKey.currentState.removeItem(index,
                (context, animation) => buildItem(context, index, animation),
                duration: const Duration(milliseconds: 300));
            mainProvider.list.removeAt(index);
            mainProvider.addCount();
          },
          child: Card(
            child: Padding(
              padding: const EdgeInsets.all(32.0),
              child: _widget,
            ),
          ),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(),
      body: Container(
        color: Colors.white,
        child: Padding(
          padding: const EdgeInsets.all(32.0),
          child: mainProvider.list == null
              ? Container()
              : AnimatedList(
                  key: listKey,
                  initialItemCount: mainProvider.list.length,
                  itemBuilder:
                      (BuildContext context, int index, Animation animation) =>
                          buildItem(context, index, animation),
                ),
        ),
      ),
    );
  }
}

【问题讨论】:

  • 您如何使用该提供程序?你在哪里通过ChangeNotifierProvider 添加它,你在哪里用Consumer 获取它(或类似)?
  • 嗨@Abion47,感谢您有兴趣提供帮助。我有一个父 ChangeNotifierProvider 小部件,我通过子小部件上的 Provider.of(context) 访问它的内容。我通过小部件构建下的 Provider.of 访问值,而我只使用消费者小部件,因为它的子小部件是在 initList 期间构建的。
  • @Abion47,我更新了我的问题以显示有关如何访问它们的示例代码。希望对您有所帮助!

标签: flutter dart flutter-provider


【解决方案1】:

您正在从StatelessWidget 检索您的提供程序。因此,ChangeNotifier 无法触发您的小部件重建,因为没有要重建的状态。您必须将ParentWidget 转换为StatefulWidget,或者您需要使用Consumer 而不是Provider.of 让您的提供者:

class ParentWidget extends StatelessWidget {
  final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();

  @override
  Widget build(BuildContext context) {
    return Consumer<MainProvider>(
      builder: (BuildContext context, MainProvider mainProvider, _) {
        ...
      }
    );
  }

顺便说一句,您使用提供程序的方式是将MainProvider 添加到其提供程序,然后从其直接子项中检索它。如果这是您检索MainProvider 的唯一位置,这会使提供者模式变得多余,因为您可以轻松地在ParentWidget 中声明它,或者甚至只是使用FutureBuilder 获取图像列表。使用提供程序是实现正确状态管理的良好一步,但也要小心过度设计您的应用程序。

【讨论】:

  • 对于无状态小部件使用 Consumer 而不是 Provider.of 会更好吗?
  • 你知道,我之前就已经在想,我可能在这里过度设计了我的工作,甚至可能只是用更简单的解决方案侥幸逃脱。在继续之前,我只是在寻找可以使用的有效方法。这让我真正思考,谢谢!
  • @AverageCoder 您必须在无状态小部件中使用Consumer。否则模型中的更改不会触发 UI 的重建。
  • 只是补充一点,您也可以使用:context.read() 来访问和读取提供程序。也同意@Abion47 所说的一切
  • @DruhinBala 使用context.read&lt;T&gt;() 的问题在于它是一个包装Provider.of&lt;T&gt;(context, listen: false) 的扩展方法,因此它不会注册调用小部件来监听和重建更新。一般来说,这是一个很好的捷径,但在这种情况下它对 OP 没有帮助。
猜你喜欢
  • 2021-01-08
  • 2020-12-22
  • 2020-08-31
  • 2020-06-03
  • 2019-10-08
  • 2022-01-01
  • 2010-11-11
  • 2016-10-18
  • 2021-10-15
相关资源
最近更新 更多