skip to Main Content

Considering we have a function like following that loads up data from database:

  loadData() async {
    loadedData = await loadingData();
    return loadedData;
  }

And we want to use this loadedData inside the same or other class/widget using Provider package.

I tried many ways like putting loadData() inside initState() or didChangeDependencies() like following:

  @override
  void didChangeDependencies() async {
    super.didChangeDependencies();
    data = await Provider.of<>(context , listen: false).loadData();
  }

Or using Consumer or trying to pass data using ChangeNotifierProxyProvider at the startup of the application but still have problems most of the time and getting errors like null value errors or some other related errors(Can’t remember at the moment).

I like to know what is the correct way of fetching data from database and wait for data in a Widget?

For example I know if I change (listen: false) to (listen: true) within the Provider command I can read data but it seems it updates the app very much and I can hear the rising noise of the CPU fan that I don’t like it!

Please give me a simple code example/snippet to understand the correct way of doing that?

3

Answers


  1. You can use FutureBuilder to load data like this:

    class MyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
          future: Provider.of<MyData>(context, listen: false).loadData(),
          builder: (BuildContext context, AsyncSnapshot<MyData> snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(
                child: CircularProgressIndicator(),
              );
            } else if (snapshot.hasError) {
              return Center(
                child: Text('Error: ${snapshot.error}'),
              );
            } else {
              MyData data = snapshot.data!;
              // Use the loaded data to build your widget
              return Text(data.someProperty);
            }
          },
        );
      }
    }
    
    Login or Signup to reply.
  2. You can use FutureBuilder or via using turnery operators.

    data == null || data.isEmpty
    ? CircularProgressIndicator() 
    : Center(
        child: Text("It is working")
    ),
    
    Login or Signup to reply.
  3. Here is an example of loadData using the provider. If you don’t want to eager load the data, just remove initState() method.

    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
      @override
        void initState() {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            context.read<TestModel>().loadData();
          });
          super.initState();
        }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: _buildContent()
        );
      }
    
      Widget _buildContent() {
        ///context.watch only rebuild when [TestModel] changes.
        TestModel testModel = context.watch<TestModel>();
        if (testModel.isLoading) {
            return Center(child: CircularProgressIndicator());
          } else {
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(testModel.data),
                  ElevatedButton(
                    onPressed: () async => await testModel.loadData(),
                    child: Text('Click to Load Data'),
                  ),
                ],
              ),
            );
          }
        }
      }
    
    class TestModel with ChangeNotifier {
      String _data = '';
      bool _isLoading = false;
    
      String get data => _data;
      bool get isLoading => _isLoading;
    
      Future<void> loadData() async {
        _isLoading = true;
        notifyListeners();
        // your logic here
        await Future.delayed(Duration(seconds: 2));
        _data = 'Finish loading data with result';
        _isLoading = false;
        notifyListeners();
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search