Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly fetch APIs using Provider in Flutter

I'm currently dealing with a problem where I need some data from an API to show it into my widgets. I've following some Provider architecture pattern, where you setState two times:

1- When data is being fetched

2- When data is already fetched

So the problem I'm currently dealing is, my widget throws the following error:

setState() or markNeedsBuild() called during build.

I know this error is because setState is called during build, but.. how can I fetch my api during build, and then show it to my widgets? Here is my code:

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

BaseModel

 ViewState _state = ViewState.Idle;

  ViewState get state => _state;

  void setState(ViewState viewState) {
    _state = viewState;
    notifyListeners();
  }
like image 703
Nikssj_ Avatar asked Feb 11 '20 02:02

Nikssj_


People also ask

How to fetch data from an API in flutter?

This article shows you a couple of different approaches to fetch data from APIs in Flutter. The first approach is using the HttpClient class and the second one is to use the http plugin from pub.dev.

How to add http package in flutter project?

If you are starting a project from scratch, you can create a new flutter project by using IDE or command. If you already have a flutter project skip this step. To add the http package, open your pubspec.yaml file and add the http package under the dependencies section. You can get the latest version of http package on pub.dev/packages/http.

What are the problems faced by flutter beginners?

Handling network requests and integrating APIs is one of the problems faced by Flutter beginners. Even I have faced these problems while developing Flutter applications. Converting JSON to dart objects, making a network call, state management, are a few things we have to consider while integrating APIs in a Flutter app.

What is the use of build () method in flutter?

Flutter calls the build () method often when it wants to change anything in the UI. If you leave the fetch call in your build () method, It will flood the API with unnecessary calls and slow down your app. So, you need to hit the API only when needed.


1 Answers

You can use WidgetsBinding.instance.addPostFrameCallback
For detail, you can reference https://www.didierboelens.com/faq/week2/

code snippet

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

  });
}
like image 198
chunhunghan Avatar answered Oct 21 '22 06:10

chunhunghan