flutter 如何从一个提供者构建一个元素列表,当提供者改变时,它从某处获取数据并引用?

velaa5lx  于 2023-03-24  发布在  Flutter
关注(0)|答案(1)|浏览(129)

你好,我在理解如何在获取数据时使用提供程序方面遇到了很多困难。
假设我有一个http服务来获取数据并更新列表:
我的供应商.dart:

class InventoryProvider extends ChangeNotifier {
  List<Item> _items = [];
  List<Item> get items => List.unmodifiable(_items);

  Future<List<Item>> fetchAllItems() async {
    _items = await ItemService().fetchAllItems();
    notifyListeners();
    return items;
  }
}

现在我想建立我的列表。我发现的唯一可行的解决方案是:
我的屏幕:

class InventoryScreen extends StatefulWidget {
  static const routeName = '/';

  const InventoryScreen({
    super.key,
  });

  @override
  State<InventoryScreen> createState() => _InventoryScreenState();
}

class _InventoryScreenState extends State<InventoryScreen> {
  final List<Item> _items = [];
  bool _isLoading = false;
  String _errorMessage = '';

  /// Fetch items
  @override
  void initState() {
    super.initState();
    _isLoading = true;
    final itemProvider = Provider.of<InventoryProvider>(context, listen: false);
    itemProvider.fetchAllItems().then((posts) {
      setState(() {
        for (Item item in posts) {
          _items.add(item);
        }
        _isLoading = false;
      });
    }).catchError((e) {
      setState(() {
        _errorMessage = e.message;
        _isLoading = false;
      });
    });
  }
  ...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
        ...
       body: _isLoading
            ? const Center(child: CircularProgressIndicator())
            : _errorMessage.isNotEmpty
                ? Center(child: Text(_errorMessage))
                : _items.isEmpty
                    ? const Center(child: Text('You do not have any item yet.'))
                    : ListView.builder(
                        itemCount: _items.length,
                        itemBuilder: (BuildContext context, int index) {
                          final item = _items[index];

                          return ListTile(

因此,这对于第一次获取的工作原理如下:

  • 它在获取数据时显示一些东西(进度指示器)。
  • 我从供应商那里获得所有数据。

它不适用于:

  • 在提供程序发生更改时刷新列表(例如,如果在访问项目详细信息时可以删除列表中的一个项目,然后重新弹出到列表)。

我尝试过的:

  • 移除listen: False。触发器:
Exception has occurred.
FlutterError (dependOnInheritedWidgetOfExactType<_InheritedProviderScope<InventoryProvider?>>() or dependOnInheritedElement() was called before _InventoryScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.)
  • 使用listen false将initState更改为didChangeDependencies:进入请求的无限循环。

有没有人能帮你解决这个问题?

2hh7jdfx

2hh7jdfx1#

在您的ImageProvider中执行以下更改:

class InventoryProvider extends ChangeNotifier {
  List<Item> items = [];

  Future<List<Item>> fetchAllItems() async {
    items.addAll(await ItemService().fetchAllItems());
    notifyListeners();
    return items;
  }
}

在您的initState中执行以下更改:

@override
  void initState() {
    super.initState();
    _isLoading = true;
    final itemProvider = Provider.of<InventoryProvider>(context, listen: false);
    itemProvider.fetchAllItems().whenComplete(() {
      setState(() {
        _isLoading = false;
      });
    }).catchError((e) {
      setState(() {
        _errorMessage = e.message;
      });
    });
  }

使用selector Package scaffold如下:

@override
  Widget build(BuildContext context) {
    return Selector<InventoryProvider, List<Item>>(
      selector: (_, provider) => provider.items,
      builder: (_, items, __) {
        return Scaffold(...);
      },
    );
  }

相关问题