Search code examples
flutterdartlifecycleflutter-providerflutter-widget

Using Provider in Widget's initState or initialising life-cycle


So while learning Flutter, it seems that initState() is not a place to use Providers as it does not yet have access to context which must be passed. The way my instructor gets around this is to use the didChangeDependencies() life-cycle hook in conjunction with a flag so that any code inside doesn't run more than once:

bool _isInit = true;

@override
  void didChangeDependencies() {
    if (_isInit) {
      // Some provider code that gets/sets some state
    }
    _isInit = false;
    super.didChangeDependencies();
  }

This feels like a poor development experience to me. Is there no other way of running initialisation code within a Flutter Widget that has access to context? Or are there any plans to introduce something more workable?

The only other way I have seen is using Future.delayed which feels a bit "hacky":

@override
  void initState() {
    Future.delayed(Duration.zero).then(() {
      // Some provider code that gets/sets some state 
    });
    super.initState();
  }

Solution

  • It's possible to schedule code to run at the end of the current frame. If scheduled within initState(), it seems that the Widget is fully setup by the time the code is running.

    To do so, you can use the addPostFrameCallback method of the SchedulerBinding instance:

    @override
      void initState() {
        super.initState();
    
        SchedulerBinding.instance.addPostFrameCallback((_) {
          // Some provider code that gets/sets some state 
        })
      }
    

    You can also use WidgetsBinding.instance.addPostFrameCallback() for this. They both behave the same for the purpose of running code once after the Widget has been built/loaded, but here is some more detail on the differences.

    Note: be sure to import the file needed for SchedulerBinding:

    import 'package:flutter/scheduler.dart';