Do not use BuildContexts across async gaps in flutter

Syed Abdul Basit
4 min readApr 18, 2023

--

After upgrading flutter then the lint is also updated to lint 2.0 and when we use context across async then it give us a warning

Your editor will starts complaining about situation like this:

Because flutter’s build process is 100% synchronous. You were breaking the rule.
So what’s the deal here? The issue is that after an asynchronous gap, your widget BuildContext could be a ticking time bomb waiting to explode the screen when you touch it.

The only safe way to build your widget is to avoid asynchronous usage of build context.

Consider below situation where button submits a form using any state-management and then pops the current screen.

The new lint rule will tell you that this line is risky, but why if you look up the lint online, you’ll see a suggestion to return early if your widget is no longer mounted. And this get to the crux of the issue, because certain event like scrolling, navigation and other severals other may have already removed your widget’s element from the tree.

It’s unsafe to call the famous .of method as passing stale BuildContexts to those method can crash your app.

The recommended fix is to do this The reliable way to confirm your BuildContext is still valid is to check the mounted property on a state class and the fix work for above problem.

The reliable way to confirm your BuildContext is still valid is to check the mounted property on a state class and the fix work for this scenario. Because if this widget is no longer mounted, something else may have already removed this page.

But does this always work?

Imagine a scenario, where instead of removing the page, you want to show a SnackBar that informs a user of an action outcomes.

Does the if not mounted return check still serve our purposes?. Probably not, because even if the element has been disposed, we still want the user to see confirmation of their actions (SnackBar). In that case, don’t conditionally return early if the widget is unmounted, but instead hold on to the reference and use like this

And use this reference after asynchronous gap.

Here’s a tricky one, what about this code which crosses an asynchronous gap then uses an BuildContext to read the MediaQuery, updates some layout calculation and call setState.

What if this widget is no longer mounted, then we definitely don’t care about updating any measurements for its children. So it’s safe to mounted check.

But what if it is still mounted?

Can an BuildContext safely read the MediaQuery and give us up-to-date values?

Normally code like this lives in the main area of your BuildMethod.

We can improve it’s performance because this code will only produce new values when the MediaQuery changes and the MediaQuery changing will always activate your widget’s didChangeDependencies method, so you can certainly move this code into that method and ensure it’s only ever run when it can possibly produce new values.

And this pattern is great because it allow us to only perform calculation and cache values one, precisely when our old values grow stale. And our BuildContext always synchronous and fresh.

--

--