在FutureBuilder中设置提供者的价值 [英] Setting provider value in FutureBuilder

查看:83
本文介绍了在FutureBuilder中设置提供者的价值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小部件,它向返回地图的api发出请求。我想做的是每次加载窗口小部件时都不会发出相同的请求,并将列表保存到 appState.myList 中。但。当我在 FutureBuilder 中执行 appState.myList = snapshot.data; 时,出现以下错误:

I have a widget that makes a request to an api which returns a map. What I would like to do is not make the same request every time the widget is loaded and save the list to appState.myList. But. when I do this appState.myList = snapshot.data; in the FutureBuilder, I get the following error:

flutter: ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
flutter: The following assertion was thrown while dispatching notifications for MySchedule:
flutter: setState() or markNeedsBuild() called during build.
flutter: This ChangeNotifierProvider<MySchedule> widget cannot be marked as needing to build because the
flutter: framework is already in the process of building widgets. A widget can be marked as needing to be
flutter: built during the build phase only if one of its ancestors is currently building. ...

sun.dart 文件:

class Sun extends StatelessWidget {
  Widget build(BuildContext context) {
    final appState = Provider.of<MySchedule>(context);
    var db = PostDB();

    Widget listBuild(appState) {
      final list = appState.myList;
      return ListView.builder(
        itemCount: list.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text(list[index].title));
        },
      );
    }

    Widget futureBuild(appState) {
      return FutureBuilder(
        future: db.getPosts(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.hasData) {
            // appState.myList = snapshot.data;
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (context, index) {
                return ListTile(title: Text(snapshot.data[index].title));
              },
            );
          } else if (snapshot.hasError) {
            return Text("${snapshot.error}");
          }
          return Center(
            child: CircularProgressIndicator(),
          );
        },
      );
    }

    return Scaffold(
        body: appState.myList != null
            ? listBuild(appState)
            : futureBuild(appState));
  }
}

postService.dart 文件:

class PostDB {
  var isLoading = false;

  Future<List<Postmodel>> getPosts() async {
    isLoading = true;
    final response =
        await http.get("https://jsonplaceholder.typicode.com/posts");

    if (response.statusCode == 200) {
      isLoading = false;
      return (json.decode(response.body) as List)
          .map((data) => Postmodel.fromJson(data))
          .toList();
    } else {
      throw Exception('Failed to load posts');
    }
  }
}

我了解< c $ c> myList 调用 notifyListeners(),这就是导致错误的原因。希望我说对了。如果是这样,如何设置 appState.myList 并在应用中使用而不会出现上述错误?

I understand that the myList calls notifyListeners() and that's what causes the error. Hope I got that right. If so, how do I set appState.myList and use in the app without getting the above error?

import 'package:flutter/foundation.dart';
import 'package:myflutter/models/post-model.dart';

class MySchedule with ChangeNotifier {
  List<Postmodel> _myList;

  List<Postmodel> get myList => _myList;

  set myList(List<Postmodel> newValue) {
    _myList = newValue;
    notifyListeners();
  }
}


推荐答案

这很不好,因为它可能导致小部件树不一致。一些小部件。

This is bad, as it could lead to an inconsistent widget tree. Some widget. may be built widgets using the value before mutation, while others may be using the mutated value.

解决方案是消除不一致之处。使用 ChangeNotifierProvider ,通常有两种情况:

The solution is to remove the inconsistency. Using ChangeNotifierProvider, there are usually 2 scenarios:


  • 执行的突变 ChangeNotifier 上的操作始终与创建 ChangeNotifier 的操作在同一 build 中完成

  • The mutation performed on your ChangeNotifier is always done within the same build than the one that created your ChangeNotifier.

在这种情况下,您可以直接从 ChangeNotifier 的构造函数进行调用:

In that case, you can just do the call directly from the constructor of your ChangeNotifier:

class MyNotifier with ChangeNotifier {
  MyNotifier() {
    // TODO: start some request
  }
}


  • 执行的更改可能会发生,

  • The change performed can happen "lazily" (typically after changing page).

    在这种情况下,您应该将突变包装在 addPostFrameCallback Future.microtask

    In that case, you should wrap your mutation in an addPostFrameCallback or a Future.microtask:

    class Example extends StatefulWidget {
      @override
      _ExampleState createState() => _ExampleState();
    }
    
    class _ExampleState extends State<Example> {
      MyNotifier notifier;
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        final notifier = Provider.of<MyNotifier>(context);
    
        if (this.notifier != notifier) {
          this.notifier = notifier;
          Future.microtask(() => notifier.doSomeHttpCall());
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    }
    


  • 这篇关于在FutureBuilder中设置提供者的价值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆