flutterstatelesswidgetflutter-futurebuilder

Flutter: How to fetch data from api only once while using FutureBuilder?


How can I fetch data only once while using FutureBuilder to show a loading indicator while fetching?

The problem is that every time the user opens the screen it will re-fetch the data even if I set the future in initState().

I want to fetch the data only the first time the user opens the screen then I will use the saved fetched data.

should I just use a stateful widget with a loading variable and set it in setState()?

I'm using Provider package

Future<void> fetchData() async {
try {
  final response =
      await http.get(url, headers: {'Authorization': 'Bearer $_token'});......

and my screen widget:

    class _MyScreenState extends State<MyScreen> {
  Future<void> fetchData;

  @override
  void initState() {

    fetchData =
        Provider.of<Data>(context, listen: false).fetchData();

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: fetchData,
      builder: (ctx, snapshot) =>
          snapshot.connectionState == ConnectionState.done
              ? Consumer<Data>(
                  builder: (context, data, child) => Text(data.fetchedData)): Center(
                               child: CircularProgressIndicator(),
                               ),
                        
    );
  }
}

Solution

  • If you want to fetch the data only once even if the widget rebuilds, you would have to make a model for that. Here is how you can make one:

    class MyModel{
     String value;
     Future<String> fetchData() async {
     if(value==null){
     try {
      final response =
          await http.get(url, headers: {'Authorization': 'Bearer $_token'});......
     value=(YourReturnedString)
      }
     }
      return value;
     }
    }
    

    Don't forget to place MyModel as a Provider. In your FutureBuilder:

    @override
      Widget build(context) {
        final myModel=Provider.of<MyModel>(context)
        return FutureBuilder<String>(
          future: myModel.fetchData(),
          builder: (context, snapshot) {
            // ...
          }
        );
      }