flutter-stateless-vs-stateful

StatelessWidget and StatefulWidget in Flutter

  • 4 min

A stateful widget is a component that remembers information and can redraw itself.

We’ve already created our first App and know that “everything is a Widget.” But you’ll soon realize there are two types of Widgets, and choosing between them defines how your application behaves.

We’re talking about StatelessWidget and StatefulWidget.

Understanding this difference will allow you to decide where the state should live and which part of the interface needs to be rebuilt.

The concept of state

Before looking at the code, let’s define what State is.

State is the information that can change over time in your Widget and affects how it looks on screen.

  • The text of a counter (0, 1, 2…).
  • Whether a checkbox is checked or not.
  • The color of a button when you press it.

If a piece of data changes and you want the screen to update to reflect that change, that is State.

StatelessWidget

A StatelessWidget is immutable: its properties do not change during the lifetime of that instance. However, Flutter can replace it with another configuration and re-execute its build method.

Think of it as a photograph. Once developed, the photo doesn’t change. If you want the person in the photo to smile, you can’t modify the photo: you have to throw away the old photo and take a new one.

When to use it?

When the part of the interface you are describing does not depend on any user interaction or internally changing data.

  • An icon.
  • A static text (“App Title”).
  • A colored container.

Structure

It’s very simple. We only override the build method.

class MySimpleButton extends StatelessWidget {
  // Properties MUST be final (immutable)
  final String text;

  const MySimpleButton({required this.text});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      color: Colors.blue,
      child: Text(text),
    );
  }
}
Copied!

Flutter is extremely fast at creating and destroying StatelessWidgets. Don’t be afraid to use and nest them.

StatefulWidget

A StatefulWidget is also immutable, but it delegates the mutable information to a separate State object. This state can change in response to taps, data from the internet, or timers.

Think of it as a video or a robot. It can move, change color, and react.

The two-class architecture

This is where beginners get confused. A StatefulWidget is not a single class; it’s two:

  1. The Widget: It is immutable (like the Stateless one). It serves only as configuration.
  2. The State (State): This is where the logic and mutable data live. This class persists even if the screen is redrawn.

Why two classes? For performance. Flutter can rebuild the UI (the Widget) thousands of times per second, but it keeps the State object in memory so you don’t lose your data (like the counter value).

Structure and setState

Let’s look at the classic counter example. Pay attention to the setState method.

// 1. The Widget class (Public and Immutable)
class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

// 2. The State class (Private _ and Mutable)
class _CounterWidgetState extends State<CounterWidget> {
  
  // Here we CAN have variables that are not final
  int _counter = 0;

  void _increment() {
    // setState tells Flutter that something changed
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('Clicks: $_counter'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _increment, // Call the function on press
        child: Icon(Icons.add),
      ),
    );
  }
}
Copied!

The setState() method

When you change the value of _counter++, Dart updates the variable, but the screen doesn’t know about it. The screen still shows “0”.

By wrapping the change inside setState( () { ... } ), you are telling Flutter:

“I have changed a piece of data that affects the interface. Schedule a rebuild of this sub-tree with the updated data.”

If you forget the setState, your variable will change, but the interface will remain frozen.

Which one do I choose?

Here is the golden rule we use:

  1. Always start with a StatelessWidget. It is lighter and easier to read.
  2. Do you need that widget to change (color, text, shape) when the user interacts with it? -> Convert it to a StatefulWidget.
  3. Does the change come from outside (the parent passes it new data)? -> Stay with a StatelessWidget (the parent will handle rebuilding it).