Reputation: 253
I have a method that returns one of two stateful widgets, based on the value of an enum. However, even though I can see via the debugger that the "correct" widget is being returned, the UI only ever shows the first one that is rendered. It seems the state object is somehow being shared across different instances of the widget, or I'm missing something.
Widget _buildInfoCard(LoginStatus status) {
switch(status) {
case LoginStatus.LOGIN_FAILED:
return InfoCard("Login failed, please check your username and password.");
default:
return InfoCard("Please login with your username and password");
}
}
I expect that the displayed infocard will have the text that corresponds to the text of the returned info card, but the default case always presents. I've stepped through the code, the correct widget is returned, and the default widget is not returned after that, so it should be displayed, but does not.
EDIT: The _buildInfoCard method gets called inside of a streambuilder.
Upvotes: 0
Views: 413
Reputation: 253
For anyone with the same issue - follow the link provided by Jordan Davies, then watch episode 2 of Flutter 101 on YouTube for more information.
The issue is that as you construct your widget tree, the flutter framework translates those widgets into elements, which it then uses to render the UI.
When the flutter framework is constructing the element tree, it looks at each widget and compares the widget type to the element type at a given position in the tree. If the types are the same, flutter may re-use the element.
Stateful widgets have a long-lived state object, they may not get deleted with the wrapping element when a new one added to the element tree. In this case, the newly returned widget may use an existing state object from a previously rendered stateful widget.
The solution is as Jordan suggested, use keys to prevent this from hapenning, or use stateless widgets. There are other methods on Stateful widgets that may work as well, but Jordan's answer best addresses my expectations.
Upvotes: 1
Reputation: 10861
You need to give each instance of your StatefulWidget
a key otherwise they may share state, something like this:
Widget _buildInfoCard(LoginStatus status) {
switch (status) {
case LoginStatus.LOGIN_FAILED:
return InfoCard(
key: ValueKey(status),
message: "Login failed, please check your username and password.",
);
default:
return InfoCard(
key: ValueKey(status),
message: "Please login with your username and password",
);
}
}
Very good article about why we need keys here: https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
Upvotes: 2