Closed jonl-percsolutions-com closed 1 week ago
Additional. I have a custom component that contains an optional header and a list. If there is a header, the list is collapsible, and is supposed to start collapsed. If there is no header, the list is shown initially as open. This is driven by a state variable.
The below is generated which causes the widget to flash across the screen, display correctly, then redraw multiple times incorrectly:
void initState() {
super.initState();
_model = createModel(context, () => ProtocolItemListViewModel());
// On component load action.
SchedulerBinding.instance.addPostFrameCallback((_) async {
_model.showList = widget.headerItem == null;
});
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
}
Hey @joni-percsolutions-com thanks for your report. I have confirmed that the generated code is not the ideal, and this could lead to some unexpected behaviour (as the ones you mentioned). I will send this to our technical team, they will review it and keep you updated on this thread.
Have a great day!
Hi @jonl-percsolutions-com, thanks for the bug report! This is done intentionally since there are some cases where we can't immediately access some values in initState
, thus requiring us to use a postframe callback instead. Hope this clears things up for you!
Hi @jonl-percsolutions-com, thanks for the bug report! This is done intentionally since there are some cases where we can't immediately access some values in
initState
, thus requiring us to use a postframe callback instead. Hope this clears things up for you!
@takashiff , No this doesn't clear things up for me because, as mentioned in my ticket, it causes flickering bug in my UI. It would make sense, that the developer should be able to say whether or not the initState functions are async.
It also does not make sense for there to be an empty set state within the initState , that is also posted in a postframe callback. that forces a redraw. There are much better ways to handle it and it should only be added when necessary, if it is ever necessary because it is a surprise that it would do it at all.
A single postFramecallback that waits for access to a value would make possible sense, if it were conditionally added based upon the code generated, but the current set up make absolutely no sense whatsoever.
Has your issue been reported?
Current Behavior
Problem 1:
It appears all generated widget have a postframe callback to setState(). This causes in many cases, an unnecessary rebuild of the widget. Which can be a performance issue and undesired behavior.
Problem 2:
If you add a initialization action to a component or widget, it is also added to a postframeCallback. This means that the initialization action occurs AFTER the first build, requiring another rebuild for the proper state to be updated.
So, besides the performance penalty and flashing screens caused by unnecessary redrawing, there is a non-deterministic element to these updates as well, because one may use an async call back with or without an await and the set state callback is not awaited.
Depending on whether you thought it was silly to rebuild in an initialization action, this causes non-intuitive and hard to determine behavior in the application.
Expected Behavior
Everything generated in an initState,unless explicitly desired to complete after the fact, should complete by the time that the initState function is complete. using postFrameCallback, from my experience, in an initialization method, is a recipe for race conditions. IE, if say, the widget is accessed in postFrameCallback, the parent widget in a stateful widget is accessed in a postframe callback, it could be disposed by the time it's accessed due to a redraw or modified by the flutter framework due to intervening redraws.
Steps to Reproduce
Reproducible from Blank
Bug Report Code (Required)
n/a
Context
I am trying to initialize a state variable that drives the visibility of a local widget, that is updated based upon a user interaction. This behavior is causing unintended side effects because of the race condition generated, like flashing redraws and unexpected state after a redraw.
Visual documentation
Generates the below. Rebuilding the widget should be unnecessary.
The below would work just as well without forcing any redraws:
///
Additional Info
No response
Environment
General
Relative to the time the changes were made, data was lost within
When following my steps to reproduce, data loss happens