58

I am calling initial method to load data from API using initState. But it is resulting me an error. Here is error:

Unhandled Exception: inheritFromWidgetOfExactType(_LocalizationsScope) or inheritFromElement() was called before _ScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.

My code is:

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

    this._getCategories();
  }

  void _getCategories() async {
    AppRoutes.showLoader(context);
    Map<String, dynamic> data = await apiPostCall(
      apiName: API.addUser,
      context: context,
      parameterData: null,
      showAlert: false,
    );
    if(data.isNotEmpty){
      AppRoutes.dismissLoader(context);
      print(data);

    }else {
      AppRoutes.dismissLoader(context);
    }
   }
Code Hunter
  • 10,075
  • 23
  • 72
  • 102

6 Answers6

124

You need to call _getCategories after initState has completed.


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

   Future.delayed(Duration.zero, () {
      this._getCategories();
   });

   // Could do this in one line: Future.delayed(Duration.zero, this._getCategories);
}

Also, you could do this on a different way, using addPostFrameCallback. To make this task easier, you could create a mixin to be added to StatefulWidgets.

mixin PostFrameMixin<T extends StatefulWidget> on State<T> {
  void postFrame(void Function() callback) =>
      WidgetsBinding.instance?.addPostFrameCallback(
        (_) {
          // Execute callback if page is mounted
          if (mounted) callback();
        },
      );
}

Then, you just need to plug this mixin to you page, like that:

class _MyPageState extends State<MyPage> with PostFrameMixin {
  @override
  void initState() {
    super.initState();

    postFrame(_getCategories);
  }
}

siega
  • 2,508
  • 1
  • 19
  • 22
40

Use the didChangeDependencies method which gets called after initState.

For your example:

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

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

  this._getCategories();
}

void _getCategories() async {
  // Omitted for brevity
  // ...

 }
Emilio Brandon Flanagan
  • 1,142
  • 1
  • 12
  • 13
  • 15
    This is could result in multiple calls to _getCatergories() as didChangeDependencies() is called multiple times. So if the _getCatergories() involves network calls or refreshing state, this would be very bad. – Susheel Karam Apr 28 '20 at 07:44
  • this works not only for this case but also for this other question https://stackoverflow.com/questions/60363665/dependoninheritedelement-was-called-before-initstate-in-flutter – Obum Feb 17 '22 at 10:02
35

Adding a frame callback might be better than using Future.delayed with a zero duration - it's more explicit and clear as to what is happening, and this kind of situation is what frame callback was designed for:

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

    WidgetsBinding.instance.addPostFrameCallback((_) async {
      _getCategories();
    });
  }
James Allen
  • 6,406
  • 8
  • 50
  • 83
8

an alternative is to put it inside PostFrameCallback which is between initState and Build.

@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => getData());
}
    
Future<void> getData() async {
// perform fetch logic
}
MJ Montes
  • 3,234
  • 1
  • 19
  • 21
2

There are many ways to solve this problem, override initState method:

@override
void initState() {
  super.initState();
  // Use any of the below code here. 
}
  • Using SchedulerBinding mixin:

    SchedulerBinding.instance!.addPostFrameCallback((_) {
      // Call your function
    });
    
  • Using Future class:

    Future(() {
      // Call your function
    });
    
  • Using Timer class:

    Timer(() {
      // Call your function
    });
    
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
-1

The best solution i think is use the context from the Widget build. And paste the method _getCategories(context) after the build with the context from the tree. So there is no problem with the widget tree.

Kfarsoft
  • 59
  • 1
  • 3