Do not use BuildContexts across async gaps
2,556
Don't stock context directly into custom classes, and don't use context after async if you're not sure your widget is mounted.
Do something like this:
class MyCustomClass {
const MyCustomClass();
Future<void> myAsyncMethod(BuildContext context, VoidCallback onSuccess) async {
await Future.delayed(const Duration(seconds: 2));
onSuccess.call();
}
}
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () => const MyCustomClass().myAsyncMethod(context, () {
if (!mounted) return;
Navigator.of(context).pop();
}),
icon: const Icon(Icons.bug_report),
);
}
}
Author by
Bermjly Team
Updated on December 31, 2022Comments
-
Bermjly Team over 1 year
I have noticed a new lint issue in my project.
Long story short:
I need to use BuildContext in my custom classes
flutter lint tool is not happy when this being used with aysnc method.
Example:
MyCustomClass{ final buildContext context; const MyCustomClass({required this.context}); myAsyncMethod() async { await someFuture(); # if (!mounted) return; << has no effect even if i pass state to constructor Navigator.of(context).pop(); # << example } }
-
Mozes Ong over 2 yearsdoesn't seem wise to pass context to objects like that for the purpose of navigation. If your navigation stack changes after you have passed the context to MyCustomClass and you try to navigate again using the old context, you will get errors.
-
Bermjly Team over 2 yearsI agree, then how this scenario should be approached?
-
Mozes Ong over 2 yearsUse some state management like BloC, where you can trigger navigation when a state changes. So long as you do not store your context, but instead, use the context for navigation purposes without storing the instance.
-
-
Bermjly Team over 2 yearsUnfortunately you cannot use mounted attribute in custom class ;(
-
L Uttama over 2 yearsThis error is caused by
if (!mounted) return;
check for this variable/attributemounted
. It is giving error because you can not use thatmounted
here inside your custom class. -
Bermjly Team over 2 yearsI am not using mounted property because clearly you cannot use it in custom class.
-
Bermjly Team over 2 yearsNo be careful of doing that! context might not be mounted so absolutely this does not guarantee to fix the issue and might cause the app to crash instead!
-
Sxndrome about 2 years@BermjlyTeam I do not understand how this might not fix the issue. The BuildContext was used to fetch the Navigator instance. The resulting instance is now fetched. After the await, we must not use the BuildContext. We don't. We only use the Navigator instance. How does this not fix the issue in at least a StatelessWidget ?
-
stk about 2 yearsHow can you do it in a StatelessWidget?
-
Guildem about 2 years@stk I don't think you can, a StatelessWidget don't really have a lifecycle (no state). But if you want an async method, then you have a long-ish thing to do, and you want the app user to see something is happening, so you need a state. If you look at your app, you should see where you need to handle this state and create a Stateful widget.
-
Guildem about 2 years@Sxndrome imagine that your someFuture() waits 5 seconds (biiiiig task). During this time, you go back with Android back button or another implemented way. What //2 will do when someFuture() is finished ? Context before and after the future won't always be the same.
-
stk about 2 yearsGood point in general!
-
jaredbaszler about 2 yearsYou can't just copy and paste directly from documentation and not at least cite your source: dart-lang.github.io/linter/lints/…
-
Jim Gomes almost 2 yearsThis is very close to being the correct answer. It just needs a check before calling navigator.pop(). Change to
if (navigator.mounted) navigator.pop();
I would also store the NavigatorState instead of BuildContext:MyCustomClass { final NavigatorState navigator; const MyCustomClass(this.navigator); }
Example instantiation:final obj = MyCustomClass(Navigator.of(context));
-
M Karimi almost 2 years@stk In stateless widget, you can use this: stackoverflow.com/a/69512692/11675817