Can a StatelessWidget contain member variables?

Issue

I have a StatelessWidget that uses a ScopedModel to store its data. The widget basically presents a list of checkboxes and some buttons to save the state of the checked boxes.

Now I want to keep track of if the user has altered any of the checkboxes, i.e. checked/unchecked them since the widget was displayed. So I added something like this:

class MyCheckboxScreen extends StatelessWidget{

    bool _hasBeenModified = false;

    void _itemCheckedChange(bool checked, MyModel model){
        _hasBeenModified = true;

        // Code to change the model here
    }


    void _onCloseButton(){
        if( _hasBeenModified ){
            // Show a warning that there are modifications that will not be be saved
        }
    }


    void _onSaveButton(Context context, MyModel model){
        model.save();
        Navigator.of(context).pop();
    }

}

This seems to work, but my StatelessWidget now contains its own state.

The state isn’t used to update the UI and redraw anything, it’s only used to check if there are modifications to any checkbox when pressing the "Close" button.

Is it safe for a StatelessWidget to have this kind of internal state? Or could it be a problem? For example, could the widget be recreated unexpectedly, and the internal state lost?

I don’t find the documentation to be very clear on this, it just says

For compositions that can change dynamically, e.g. due to having an internal clock-driven state, or depending on some system state, consider using StatefulWidget.

But this sounds like it only applies to state that affects the UI and requires rebuilding the widget.

Solution

Yes, a StatelessWidget can have mutable variables (your code compiles) but that’s wrong.

A widget that does not require mutable state

This is taken from the documentation. Even if you have a single non-final variable, it means that something can actually be changed in your widget. It’s not an immutable class. Ideally, you should use StatelessWidgets like this:

class MyWidget extends StatelessWidget {
  final int a;
  final String b;
  const MyWidget(this.a, this.b);
}

Or something similar such as

class MyWidget extends StatelessWidget {
  const MyWidget();
}

When you have non final variables, use a StatefulWidget. Your class has to clearly be a StatefulWidget:

// This is not final. It can be changed (and you will change it)
// so using the stateless way is wrong
bool _hasBeenModified = false;

void _itemCheckedChange(bool checked, MyModel model){
  _hasBeenModified = true;
}

The UI doesn’t matter actually because here’s a matter of variables and mutability. Something is changing (bool _hasBeenModified) so it cannot be a StatelessWidget because it has to be used in all those cases where the state is immutable.

Answered By – Alberto Miola

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *