141 lines
4.5 KiB
Plaintext
141 lines
4.5 KiB
Plaintext
The https://api.flutter.dev/flutter/widgets/StatefulWidget/createState.html[`createState` method of a `StatefulWidget`] should return a brand new https://api.flutter.dev/flutter/widgets/State-class.html[`State`] object, and do nothing more than that.
|
|
|
|
== Why is this an issue?
|
|
|
|
A Flutter widget is said to be stateful if it has a mutable state that can change over time. More accurately, a widget is stateful when it defines a piece of user interface that may change appearance or behavior over time. Such changes of appearance or behavior are modelled into variations of the internal state of the widget.
|
|
|
|
The state defined in a stateful Flutter widget is https://docs.flutter.dev/data-and-backend/state-mgmt/ephemeral-vs-app[ephemeral], meaning that it is not persistent and is not to be shared between different instances of the same widget.
|
|
|
|
This is because in most cases, the state of a widget is local and doesn't need to be accessed by other widgets in the components tree. Therefore, the Flutter framework can make simplifying assumptions on the lifecycle of such a state, incapsulating it in the `StatefulWidget` class, that exposes the https://api.flutter.dev/flutter/widgets/StatefulWidget/createState.html[`createState` method].
|
|
|
|
The `createState` method is called by the framework whenever a new instance of the widget is created, and should only create a new state object.
|
|
|
|
[source,dart]
|
|
----
|
|
import 'package:flutter/widgets/framework.dart';
|
|
|
|
class MyState extends State<MyStatefulWidget> {
|
|
int i1 = 42;
|
|
|
|
MyState() { }
|
|
}
|
|
|
|
class MyStatefulWidget extends StatefulWidget {
|
|
@override
|
|
MyState createState() => MyState();
|
|
}
|
|
----
|
|
|
|
=== What is the potential impact?
|
|
|
|
Doing more than creating a new instance in the `createState` method can lead to unexpected behavior. For example, if a state object is cached in a top-level variable and reused across multiple instances of the same widget, a change in the state of one instance will affect all other instances sharing the same state object.
|
|
|
|
== How to fix it
|
|
|
|
Remove the logic from the `createState` method, or move it to the appropriate location.
|
|
|
|
* Any logic that reuses an already existing state object should be removed, as it violates the design of `StatefulWidget`.
|
|
* Any logic that is related to editing the new `State` object should be moved to the construction phase of the `State` or to the `State.initState` method.
|
|
* Any logic that is temporarily storing the newly created `State` object should be removed, and the object should be returned directly.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,dart,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
late MyState global;
|
|
|
|
class MyState extends State<MyStatefulWidget> {
|
|
int i1 = 42;
|
|
|
|
MyState() { }
|
|
}
|
|
|
|
class MyStatefulWidget extends StatefulWidget {
|
|
@override
|
|
MyState createState() {
|
|
global = MyState(); // Non compliant: global state object is reused
|
|
return global;
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,dart,diff-id=1,diff-type=compliant]
|
|
----
|
|
class MyState extends State<MyStatefulWidget> {
|
|
int i1 = 42;
|
|
|
|
MyState() { }
|
|
}
|
|
|
|
class MyStatefulWidget extends StatefulWidget {
|
|
@override
|
|
MyState createState() => MyState();
|
|
}
|
|
----
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,dart,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
class MyState extends State<MyStatefulWidget> {
|
|
int i1 = 42;
|
|
|
|
MyState() { }
|
|
}
|
|
|
|
class MyStatefulWidget extends StatefulWidget {
|
|
@override
|
|
MyState createState() {
|
|
final myState = MyState();
|
|
myState.i1 = 43;
|
|
return ;
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,dart,diff-id=2,diff-type=compliant]
|
|
----
|
|
class MyState extends State<MyStatefulWidget> {
|
|
int i1 = 43;
|
|
|
|
MyState() { }
|
|
}
|
|
|
|
class MyStatefulWidget extends StatefulWidget {
|
|
@override
|
|
MyState createState() => MyState();
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* Dart Docs - https://dart.dev/tools/linter-rules/no_logic_in_create_state[Dart Linter rule - no_logic_in_create_state]
|
|
* Flutter API Reference - https://docs.flutter.dev/data-and-backend/state-mgmt/ephemeral-vs-app[State management - Differentiate between ephemeral state and app state]
|
|
* Flutter API Reference - https://api.flutter.dev/flutter/widgets/StatefulWidget/createState.html[StatefulWidget class - createState abstract method]
|
|
* Flutter API Reference - https://api.flutter.dev/flutter/widgets/State-class.html[State class]
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Don't put any logic in 'createState'.
|
|
|
|
=== Highlighting
|
|
|
|
The entire body of the `createState` method, including the braces, when present.
|
|
|
|
endif::env-github,rspecator-view[]
|