如何在 Flutter 中使用 Provider 正确获取 API

Posted

技术标签:

【中文标题】如何在 Flutter 中使用 Provider 正确获取 API【英文标题】:How to correctly fetch APIs using Provider in Flutter 【发布时间】:2020-05-26 09:29:25 【问题描述】:

我目前正在处理一个问题,我需要来自 API 的一些数据才能将其显示到我的小部件中。我遵循了一些 Provider 架构模式,您在其中 setState 两次:

1- 获取数据时

2- 当数据已经被获取时

所以我目前正在处理的问题是,我的小部件抛出以下错误:

setState() or markNeedsBuild() called during build.

我知道这个错误是因为在构建过程中调用了 setState,但是.. 如何在构建过程中获取我的 api,然后将其显示给我的小部件?这是我的代码:

NewsPage.dart

    class HomePage extends StatefulWidget 
  @override
  _HomePageState createState() => _HomePageState();


class _HomePageState extends State<HomePage> 
  SideBarWidget _sidebar;

  @override
  void initState() 
    Provider.of<HomeViewModel>(context, listen: false)
        .fetchUltimaNoticia(context); --> ****Data to get fetched****
    _sidebar = const SideBarWidget();
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: const Text('INICIO'),
        centerTitle: true,
        automaticallyImplyLeading: false,
        leading: Builder(
          builder: (context) => IconButton(
            icon: const Icon(Icons.menu),
            onPressed: () => Scaffold.of(context).openDrawer(),
          ),
        ),
      ),
      drawer: _sidebar,
      body: FormNoticiaContainer(),
    );
  

FormContainer()

Widget build(BuildContext context) 
    return _crearBodyNoticia(context);
  

  Widget _crearBodyNoticia(context) 
    final homeVm = Provider.of<HomeViewModel>(context, listen: true);
    return homeVm.state == ViewState.Busy
        ? Center(child: CircularLoading())
        : Center(
            child: DataToShowWidget()

HomeViewModel.dart

    class HomeViewModel extends BaseModel 
  ////////
  //NOTICIAS
  ////////

  NoticiaDB _noticia;

  NoticiaDB get noticia => _noticia;

  set setNoticia(NoticiaDB noticia) 
    _noticia = noticia;
  

  Future fetchUltimaNoticia(BuildContext context) async 
    setState(ViewState.Busy);

    var response = await noticiaProvider.obtenerNoticiaPublicada();

    setNoticia = response;

    setState(ViewState.Idle);
  

基础模型

 ViewState _state = ViewState.Idle;

  ViewState get state => _state;

  void setState(ViewState viewState) 
    _state = viewState;
    notifyListeners();
  

【问题讨论】:

您在build 期间不获取。使用FutureBuilder。见***.com/a/60141803/7034640 同理,如果我使用 FutureBuilder 获取,setState 将再次被调用,问题将是相同的.. 不一样。错误不会发生。 我的意思是是的,因为如果我将 API 的 fetch 放在 future builder 中,那么循环将是:Futurebuilder -> Builds -> Fetch Api inside futurebuilder(Which setState) -> 然后再次重建 - > 调用futurebuilder -> ......再次进行相同的循环 如果您打算继续使用HomeViewModel 方法,请使用包提供商的Consumer 而不是Provider.of 【参考方案1】:

您可以使用WidgetsBinding.instance.addPostFrameCallback 详情可以参考https://www.didierboelens.com/faq/week2/

代码sn-p

@override
void initState()
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_)
    Provider.of<HomeViewModel>(context, listen: false)
    .fetchUltimaNoticia(context);  

  );

【讨论】:

这如我所愿。这是正确的做法吗?我的意思是,如果我需要在推送新页面时获取数据,我可以毫无问题地使用它吗? 是的。没有任何问题。 @NicoAybar,如果对您有帮助,请将其标记为答案。谢谢。

以上是关于如何在 Flutter 中使用 Provider 正确获取 API的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何在 Flutter 中使用 Switch 更改主题 - 我已经使用 Provider 实现了这个明暗主题,但不能使用 switch 更改

如何使用 Provider 实现 Flutter 本地化?

如何在 Flutter 中将 textEditiing 控制器与 Provider 一起使用

如何在 Flutter 中正确重用 Provider

如何使用 Flutter 中的 Provider 增加电子商务购物车中的商品数量

Flutter - Provider - 如何根据 Provider 的值更改 UI?