Stateless Vs Stateful Widgets

Before understanding the difference between Stateless and Stateful Widgets, let's understand what is the state.

State

A state of the widget is the set of properties of that widget, that can be read synchronously at the time of building the widget. It can be changed runtime, and when it does, the widget is redrawn itself.

Stateless Widgets

Widgets that do not, can not change its state over time. Since the state doesn't change, the widget is not redrawn.

Let's have a look at the following code.

import 'package:flutter/material.dart';

class LoadingScreen extends StatelessWidget {
  const LoadingScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Expanded(
      child: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

In this code, LoadingScreen is a stateless widget, in which we have an overridden build() method which takes in BuildContext as a parameter and returns Widget. This is the method where the UI of this screen is designed, which is Stateless.

Since the widget doesn't change its state, the build() method is called only once. Hence, the widget is drawn only once. It just displays the circular progress bar in the UI.

Stateful Widgets

Widgets that change their set of properties over time. Since the state changes over time, the widget is redrawn, as I have already discussed in the previous article that UI is the function of state i-e: UI = f(state).

Let's have a look at the following code.

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

In this example code, the name of the widget is MyHomePage which extends StatefulWidget. But instead of overriding the build() method, createState() method which returns the instance of the _MyHomePage.

This class _MyHomePage extends from State. Now, this class has overridden the build() method where the whole UI of the screen is designed.

In this class, we have a private field _counter (any variable, function and class name start with "_" is called private) which is initialised as 0 and the _incrementCounter() is defined which has a callback of setState(). So this setState() method triggers the build() method which then redraws the UI.

Deep dive into build() method, we return Scaffold widget which has parameters appBar, body and floatingActionButton. In the body parameter, we have a Column widget that has two Text() widgets in the children, one has a constant text, and the other one has _counter which is changed over time.

Now, have a look at floatingActionButton, it initialises FloatingActionButton() widget that takes onPressed, and child parameters. In onPressed, we pass _incrementCounter() function.

So every time a user clicks on this button _counter is incremented inside the setState() function and this function triggers the build() method which redraws the UI and the new counter value is displayed in the UI.

Conclusion

The basic difference between the Stateless and the Stateful widget is changing the state over time. Widgets that don't change their states over time are called Stateless Widgets, and widgets that change their states over time are called Stateful Widgets. As UI = f(state), stateful widgets change their states, so the UI is redrawn.