-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Labels
P3A lower priority bug or feature requestA lower priority bug or feature requestarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.For issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-linterIssues with the analyzer's support for the linter packageIssues with the analyzer's support for the linter packagelinter-lint-proposallinter-set-flutterlinter-status-pendingtype-enhancementA request for a change that isn't a bugA request for a change that isn't a bug
Description
use_set_state_synchronously
I propose a new lint, akin to its counterpart, use_build_context_synchronously
, but for setState() invocations.
Description
Use setState() synchronously and guard it with a mounted check if needed.
Details
Using setState() after an async gap is potentially unsafe. Consider guarding it with a mounted check.
We should consider both explicit await
s and sync/async versions of the then/catchError/whenComplete callbacks.
Kind
It guards against errors.
Bad Examples
await Future.value(42);
setState(() {});
await Future.value(42).then((int value) {
setState(() {});
});
await Future.value(42).then((int value) async {
await Future<void>.delayed(const Duration(seconds: 1));
setState(() {});
});
await Future.value(42).catchError((Object error, StackTrace stackTrace) {
setState(() {});
});
await Future.value(42).whenComplete(() {
setState(() {});
});
Good Examples
await Future.value(42);
if (mounted) {
setState(() {});
}
await Future.value(42);
if (!mounted) {
return;
}
setState(() {});
await Future.value(42);
if (!context.mounted) {
return;
}
setState(() {});
await Future.value(42).then((int value) {
if (!mounted) {
return;
}
setState(() {});
});
await Future.value(42).then((int value) async {
await Future<void>.delayed(const Duration(seconds: 1));
if (!mounted) return;
setState(() {});
});
await Future.value(42).catchError((Object error, StackTrace stackTrace) {
if (!mounted) {
return;
}
setState(() {});
});
await Future.value(42).whenComplete(() {
if (!mounted) {
return;
}
setState(() {});
});
Discussion
I have seen bugs (both in the framework and in user code) due to bad usages of setState()
after an async gap.
Discussion checklist
- List any existing rules this proposal modifies, complements, overlaps or conflicts with.
- List any relevant issues (reported here, the SDK Tracker, or elsewhere).
- If there's any prior art (e.g., in other linters), please add references here.
- If this proposal corresponds to Effective Dart or Flutter Style Guide advice, please call it out. (If there isn't any corresponding advice, should there be?)
- If this proposal is motivated by real-world examples, please provide as many details as you can. Demonstrating potential impact is especially valuable.
nate-thegrate and FMorschel
Metadata
Metadata
Assignees
Labels
P3A lower priority bug or feature requestA lower priority bug or feature requestarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.For issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-linterIssues with the analyzer's support for the linter packageIssues with the analyzer's support for the linter packagelinter-lint-proposallinter-set-flutterlinter-status-pendingtype-enhancementA request for a change that isn't a bugA request for a change that isn't a bug