flutterflutter-layoutstatefulwidgetstatelesswidgetflutter-state

Why does a child state of StatefulWidget doesn't get reset when constructor parameter changes?


I have a custom widget class:

class FancyButton extends StatefulWidget
{
  final Function() onTap;
  final String text;
  final IconData icon;
  bool enabled;

  FancyButton({this.onTap, this.text, this.icon, this.enabled = true})

  @override
  _FancyButtonState createState()
  {
    return _FancyButtonState(onTap, text, icon, enabled);
  }
}

class _FancyButtonState extends State<FancyButton> with SingleTickerProviderStateMixin
{
  Function() onTap;
  String text;
  IconData icon;
  bool enabled;
  _FancyButtonState(this.onTap, this.text, this.icon, this.enabled);

  @override
  Widget build(BuildContext context) {
    if(!enabled)
      {
        print("build disabled");
      }
    return GestureDetector(
      onTap: onTap,
      child: Container(
          color: enabled ? Colors.red : Colors.green,
          height: 20
      ),
    );
  }
}

I'm using it like this:

Widget continueButton = new StreamBuilder(
          stream: viewModel.canFinishProfile.asBroadcastStream(),
          initialData: viewModel.canFinishProfile.value,
          builder: (builder, snapshot)
          {
            print("can finish profile " + viewModel.canFinishProfile.value.toString());
            return FancyButton(
              text: multilang.get("auth_continue"),
              enabled: viewModel.canFinishProfile.value,
              onTap: ()
              {
                viewModel.onClickedContinue.add(null);
              },
            );
          },
        )

So I'm expecting the widget to update once canFinishProfile value changes. The problem is that the FancyButton's state doesn't get updated once the canFinishProfile value changes, so an old widget view is always drawn. Note that if I change the FancyButton to be a StatelessWidget and put it's build code inside the StatelessWidget, then it redraws fine once then canFinishProfile value change. However, I need it to be a StatefulWidget for a more complex feature.


Solution

  • You State class will be able to listen to state changes in your StatefulWidget class if you use the widget property to access the state.

    You'd need to change:

    enabled ? Colors.red : Colors.green
    

    to

    widget.enabled ? Colors.red : Colors.green