Manas
Manas

Reputation: 3330

How to prevent calling http request everytime we click into the page on bottom navigation bar in flutter?

On the home page I have 4 different api calls fetching 4 different data from a wordpress site. The current way I have coded is that everytime we enter home page, in the initState(), the get _getHomePageData() function is called where the async api fetching is happening. while this is happening allDataLoaded boolean is set to false in the first place. Once the data is loaded allDataLoaded is set to true, the loading stops and the widgets are shown.

Here is the homepage widget:

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


class _HomePageState extends State<HomePage> {

  final String homePageLatestArtworkApi = 
  'https://example.com/wp-json/wp/v2/artworks? 
   per_page=1&_embed';
  final String homePageAllArtworkApi = 
  'https://example.com/wp-json/wp/v2/artworks? 
   per_page=6&_embed';
  final String homePageAllEventsApi = 
  'https://example.com/wp-json/wp/v2/events? 
   per_page=6&_embed';
  final String homePageAllVenuesApi = 
  'https:example.com/wp-json/wp/v2/venues? 
   per_page=6&_embed';

   List homePageLatestArtwork;
   List homePageAllArtworks;
   List homePageAllEvents;
   List homePageAllVenues;

   var allDataLoaded = false;



   @override
   void initState(){
     super.initState();

     print('init state is called everytime the page is loaded');
     _getHomePageData();
   }



  Future<String> _getHomePageData() async{

    var responseLatestArtwork = await http.get(Uri.encodeFull(homePageLatestArtworkApi));

    var responseAllArtworks = await http.get(Uri.encodeFull(homePageAllArtworkApi));

    var responseAllEvents = await http.get(Uri.encodeFull(homePageAllEventsApi));

    var responseAllVenues = await http.get(Uri.encodeFull(homePageAllVenuesApi));



  setState(() {

  //latest artwork
  var convertDataToJsonLatestArtwork = json.decode(responseLatestArtwork.body);
  homePageLatestArtwork = convertDataToJsonLatestArtwork;

  //All Artworks
  var convertDataToJsonAllArtworks = json.decode(responseAllArtworks.body);
  homePageAllArtworks = convertDataToJsonAllArtworks;

  // All Events
   var convertDataToJsonAllEvents = json.decode(responseAllEvents.body);
   homePageAllEvents = convertDataToJsonAllEvents;

  //All venues
   var convertDataToJson = json.decode(responseAllVenues.body);
    homePageAllVenues = convertDataToJson;


  if(homePageLatestArtwork != null && homePageAllArtworks != null && homePageAllEvents != null && homePageAllVenues != null){
    allDataLoaded = true;
  }
  // print('converted data is here');
  //print(homePageLatestArtwork);

  //print('the title is here :');


  //print(homePageLatestArtwork[0]['title']['rendered']);
  //print(homePageLatestArtwork[0]['_embedded']['wp:featuredmedia'][0]['source_url']);

  });



@override
Widget build(BuildContext context) {


if(allDataLoaded){ //wait for the data to load and show spinning loader untill data is completely loaded

  return Scaffold(
    // body: Text('title'),
    // body: Text("title: ${homePageLatestArtwork[0]['title']['rendered']} "),
    body: Container(
      child: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[ 
            // Expanded(
              Container(
              height: 200.0,
              child: Image.network(homePageLatestArtwork[0]['_embedded']['wp:featuredmedia'][0]['source_url'],
              fit: BoxFit.fill,
              width: double.maxFinite,),
              ),
              Container(
                padding: EdgeInsets.only(left:15.0,right:15.0,top:10.0),
                child: Text(homePageLatestArtwork[0]['title']['rendered'],textAlign: TextAlign.left,

                style: new TextStyle(
                      fontSize: 20.0,
                      fontFamily: 'Montserrat-Regular',
                      color: Color(0XFF212C3A),
                      fontWeight: FontWeight.bold
                      ),),
              ),
             ])
            ),
           ),
         );

    }else{

      return new Center(
        child: new CircularProgressIndicator(
      valueColor: new AlwaysStoppedAnimation<Color> . 
     (Theme.of(context).primaryColor),
    ),
  );
}

} //end of _HOMEPAGESTATE

I would like to not load every single time the home page is viewed, or let's say I just want to fetch the api data once when the app starts and let users manually pull down to refresh the data.

Upvotes: 1

Views: 2168

Answers (2)

Aizan Sagheer
Aizan Sagheer

Reputation: 1554

I hope I am not enough late. Anyhow if anyone else get the same situation not to refresh again and again you can add the following line at the end of your state. For example

 with AutomaticKeepAliveClientMixin

It should be like this:

class _HomeScreenState extends State<HomeScreen>
with AutomaticKeepAliveClientMixin

then you can add an override

 @override
bool get wantKeepAlive => true;

You are ready to rock.

Upvotes: 0

Fuxing Loh
Fuxing Loh

Reputation: 68

Method 1:

If you are just talking about data then you should have a singleton object that you can init once in initState();

class _HomePageData {
  var allDataLoaded = false;
  String contents = "";
  Future<String> _getHomePageData() async {
    // Assuming contents is the data model and you load the data into contents
    this.contents = "Loaded";
    this.allDataLoaded = true;
    return this.contents;
  }
}

final _HomePageData data = _HomePageData();

class _HomePageState extends State<HomePage> {
  String contents;

  @override
  void initState(){
    super.initState();

    if (!data.allDataLoaded) {
      data._getHomePageData().then((contents) {
        setState(() {
          this.contents = contents;
        })
      });
    } else {
      this.contents = data.contents;
    }
  }
}

Method 2:

Previously I was dealing with tabs that constantly reload every time I move to another tab. Flutter actively remove state when they are not attached to any active widget tree. The idea is to have the widget in a Stack, placed into Offstage & TickerMode to control visibility and animation.

class MyTabState extends State<MyTabPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: MyBottomBar(
        onTab: _onTab,
        currentIndex: _currentIndex,
      ),
      body: Stack(
        children: List.generate(3, (index) {
          return Offstage(
            offstage: _currentIndex != index,
            child: TickerMode(
              enabled: _currentIndex == index,
              child: getChild(index),
            ),
          );
        }, growable: false),
      ),
    );
  }
}

Upvotes: 1

Related Questions