shredding
shredding

Reputation: 5591

How to ensure code is run only once in a widget?

I do have a lot of code that looks like this:

bool _somethingFromApiLoaded = false;
Something _somethingFromApi;

loadSomething() async {
  final something = await ServiceProvider.of(context).apiService.getSomething();
  setState(() => _somethingFromApi = something);
}

@override
Widget build(BuildContext context) {
  if (!_somethingFromApiLoaded) {
      loadSomething();
      _somethingFromApiLoaded = true;
  }
}

Note how I produce a lot of boilerplate code to ensure loadSomething is only called once.

I wonder if there isn't a lifecycle method to do so that I somehow misinterpret. I can't use initState because it does not have context.

Upvotes: 1

Views: 1998

Answers (2)

oblomov
oblomov

Reputation: 544

You can use context in initState() by passing it to the widget:

class HomeScreen extends StatefulWidget {
  final BuildContext context;
  HomeScreen(this.context);

  @override
  State<StatefulWidget> createState() => new _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  bool _somethingFromApiLoaded = false;
  Something _somethingFromApi;

  loadSomething() async {
    final something = await ServiceProvider.of(widget.context).apiService.getSomething();
    setState(() => _somethingFromApi = something);
  }

  @override
  void initState() {
    super.initState();
    if (!_somethingFromApiLoaded) {
      loadSomething();
      _somethingFromApiLoaded = true;
    }
  }
}

Upvotes: 0

encubos
encubos

Reputation: 3283

I would try to a use a StatefulWidget and use initState() method.

That is the lifecycle you are referring to.

You should try to use a Future inside the initState()

  @override
  void initState() {
    super.initState(); // make sure this is called in the beggining

    // your code here runs only once

    Future.delayed(Duration.zero,() {
      _somethingFromApi = await ServiceProvider.of(context).apiService.getSomething();
    });

  }

As User gegobyte said, Context is available in the initState. But apparently can't be used for everything.

Upvotes: 3

Related Questions