Have you been wondering about what exactly is the difference between a stateless and a stateful widget?
- What are widgets?
- Stateless Widgets
- Stateful Widgets
- Concept of External Data
- Differences Between Stateless and Stateful Widgets
Widgets are the UI building blocks in Flutter. Everything that you see in a Flutter application is a widget. The entire Flutter Application is itself a widget.
Widgets are classified into two main types:
1. Stateless Widgets
2. Stateful Widgets
Let's dive deeper into both the types and later discuss the differences.
Let's start by creating a new widget to get a better understanding of these concepts.
We will create a Tips Widget which will display a list of tips for programmers to view.
- An array tips which contains the list of tips we would like to show the user.
- A counter tipIndex which will track the tip which is to be shown.
- A renderable Text() which will render the tip at the current tipIndex
- A renderable RaisedButton() with the label Next which on clicked will render the next tip. Check out the logic of the onPressed function changeTip().
Now in this case after clicking the Next button, the tipIndex must increment and thus the next tip at the index position 1 should be rendered.
BUT IT DOESN'T :(
Because our widget is a stateless widget as it extends the class StatelessWidget.
- Stateless Widgets do not have internal states as the name suggests.
- Stateless Widgets have no method by which the UI gets re-rendered whenever the internal values change.
The only way a stateless widget can get re-rendered is by passing EXTERNAL DATA which we will talk about after understanding Stateful Widgets.
These type of widgets do have their own internal states.
We will convert our stateless tips widget into a stateful one for more understanding.
- The Tips Class now extends StatefulWidget class
- The entire logic of the tips app have been moved to _TipsState class which extends State
- Tips Class has a function createState() which returns the _TipState.
The above are the three essential changes required to convert a stateless widget to a stateful widget.
Now this is the output which we needed and the main reason it works is because of setState() method which is applied in changeTip() function
setState() is a special function only available in Stateful Widgets which updates the state of the widget and re-renders the components that are affected by the change in state.
We specify the state which is to be updated in setState() function [we incremented tipIndex]
In our case, only the Text() which displays the tip is re-rendered because only that widget is associated with the change in tipIndex.
Now, let's discuss how Stateless Widgets can get re-rendered using External Data.
EXTERNAL DATA is the data provided to a widget through its constructor.
Now it's time we split our Tips Widget into two parts:
- TipsView (Just The Widget)
- Tips (Top Level Logic)
TipsView will just consist of renderable components Text() and RaisedButton() [Note that this is a stateless widget]
Tips will contain the top-level logic. The list of tips and the functions to handle the state change will be in this part. [This is a stateful widget]
This concept is similar to LIFTING THE STATE UP used in web frameworks.
Let us understand how a stateless widget can get-rendered.
TipsView is a stateless widget which has a constructor which takes 3 parameters tip, changeTip and tipIndex
- tip (The Tip To Be Displayed)
- changeTip (A pointer to the function which changes the tip)
- tipIndex (The Current Tip Index)
This is the top-level widget which renders the TipsView and passes down the parameters tip, tipIndex and pointer to the changeTip function.
- The build method of Tips will render the TipsView with the first tip.
- When Next button inside the TipsView will be pressed, the changeTip function residing in Tips will be called since it's pointer is passed down to TipsView.
- The tipIndex will get incremented and then the entire TipsView widget will be re-rendered with changed parameters.
Even after splitting the application it will still have the same functional result.
Note that in this case the entire stateless widget including Text() and RaisedButton() will be re-rendered and not just the Text()
So this is the use-case which shows re-rendering of stateless widgets.
- Stateless widgets have no method to re-render themselves if INTERNAL DATA changes.
- Stateless widgets can only be re-rendered when EXTERNAL DATA changes.
- If a stateless widget is re-rendered then the entire widget is re-rendered.
- Stateful widgets can be re-rendered when INTERNAL as well as EXTERNAL changes.
- The setState() method in Stateful widgets re-render components only associated with the change in state. It does not re-render the entire widget but only the necessary parts of it.