Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to define state in StatefulWidget

Problem: build() depends in StatefulWidget's state

Recently I moved a property inspector widget from being an always visible part of the UI to a Drawer.

Once I moved the property inspector, the app rendered random update operations regarding the object when the property inspector was about to edit values: The property inspector updated a random other object, not the current 'focus' object.

Solution : Make build() depend on the State<T> of StatefulWidget

I solved the issue by making the State<PropertyInspector> solely depend on state variables defined inside State<PropertyInspector> itself - instead of defining state variables in StatefulWidget and accessing these variables using widget.<someVariable>.

Root cause of the problem seems to be the fact that the Property Inspector in the Drawer gets more updates from the framework than the permanently visible alternative.

General advice

In general, Flutter needs to insert / remove / update StatefulWidget at various moments of time. While StatefulWidget might change, its State<T> object persists.

Thus, the build() method of a StatefulWidget should depend on State<T> - and not on the changing StatefulWidget.

Rules of thumb

  • All instance variables of StatefulWidget should be final
  • Thus, if an instance variable of StatefulWidget can't be marked as final, the design of the StatefulWidget is wrong.
  • From within State<T>, access to 'widget.*' instance variables are fine, as long as those variables are final.
  • Instance variables of State<T> may be non-final

Is my description correct?

This site doesn't warn about using state as widget.*. Isn't that wrong? or at least dangerous / bad style?

As far as I understand, the proposed state in StatefulWidget might work fine for some time. But, under different conditions, it is likely to render problems (as mine).

Helpful video How Stateful Widgets Are Used Best - Flutter Widgets 101 Ep. 2 in Flutter's StatefulWidget class documentation.

Contradiction

This lint error contradicts my explanation: no_logic_in_create_state

Update

I'd be happy if answers would explain, if this description / practice is correct or not.

I established this practice since certain widgets didn't behave as expected in some projects.

like image 452
SteAp Avatar asked Oct 24 '25 15:10

SteAp


1 Answers

If I have understood your description properly then I would say your rules of thumb are correct. The state class and fields persist across renders, therefore any mutable state should be enclosed within the state class not within the widget class.

The lint no_logic_in_create_state doesn't contradict this, the lint is saying no logic in the create state method, which is in the widget class.

Any mutable field in the widget class could be reset when the widget re-renders and therefore no mutable state should be kept in any widget.

I will also add that just because an instance variable in a widget is final doesn't mean it wont change within the lifecycle of the app. If you pass a prop into the widget then the instance variable would update if the prop updates (the widget would be recreated but the state wouldn't).

like image 135
Dan James Avatar answered Oct 26 '25 08:10

Dan James