What is lifecycle of widget?

person shubham sharmafolder_openFlutterlocal_offeraccess_time September 20, 2023

Understanding the widget lifecycle in Flutter is crucial for managing the state of your widgets effectively, especially when dealing with stateful widgets. Flutter provides several lifecycle methods that allow you to respond to changes in your widget’s state, from creation to destruction.

Here’s a comprehensive example illustrating the lifecycle of a stateful widget with explanations of key lifecycle methods like initState(), build(), didUpdateWidget(), dispose(), and others.

Widget Lifecycle Overview:

  1. createState(): This is called when a stateful widget is first created.
  2. initState(): Called once when the widget is inserted into the widget tree. It’s used to initialize state or set up data.
  3. didChangeDependencies(): It is called whenever the widget’s dependencies change, such as when an inherited widget that the widget relies on is modified.
  4. build(): Called whenever the widget needs to be rendered.
  5. didUpdateWidget(): Called whenever the parent widget changes the configuration of this widget (e.g., when new data is passed in).
  6. setState(): Called to update the UI based on state changes.
  7. deactivate(): Called when the widget is removed from the tree, but it can be reinserted before being disposed.
  8. dispose(): Called when the widget is permanently removed from the widget tree, used to clean up resources.

Example: Widget Lifecycle in Action

Here is an example of a Flutter app that demonstrates the lifecycle methods of a stateful widget. We’ll track the different stages of a widget’s lifecycle by printing messages to the console and visually updating the UI.

Breakdown of the Example:

  1. initState():
    • This method is called only once, when the widget is first created. It is ideal for any initialization logic or setting up resources like listeners or controllers.
    • In this example, it prints "initState() called" to the console when the widget is initialized.
  2. didChangeDependencies():
    • After the first time the widget is inserted into the widget tree (right after initState).
    • Whenever an inherited widget (like Theme or MediaQuery) that your widget depends on changes.
  3. build():
    • This method is called every time the widget is rebuilt, either after the initial creation or after setState() is called.
    • The build() method is responsible for rendering the UI.
    • In the example, it prints "build() called" every time the widget is rebuilt (e.g., when the button is pressed and _counter is incremented).
  4. didUpdateWidget():
    • This method is triggered when the parent widget rebuilds and passes new data to this widget. For instance, if the parent widget were to pass new props or a new configuration.
    • It prints "didUpdateWidget() called" when this happens.
    • In this example, it doesn’t do much because we don’t pass external data, but in more complex scenarios, you would use it to respond to changes in widget configuration.
  5. setState():
    • This is how you tell Flutter that the state of the widget has changed and it should rebuild. In this example, pressing the button increments the _counter variable and calls setState(), which triggers a rebuild of the widget and updates the text on the screen.
    • It prints "setState() called: Counter = $_counter" each time the counter is updated.
  6. deactivate():
    • This method is called when the widget is removed from the widget tree, but it hasn’t been disposed of yet. Flutter could reinsert it into the tree.
    • It prints "deactivate() called" when the widget is temporarily removed from the tree.
  7. dispose():
    • This method is called when the widget is permanently removed from the tree. It’s where you should clean up any resources, such as closing streams, cancelling timers, or disposing of controllers.
    • It prints "dispose() called" when the widget is about to be destroyed.
    • In this example, no resources are used, but typically you would clean up things like listeners, controllers, etc., here.

Widget Lifecycle Flow:

Here’s how the methods are called during a typical widget lifecycle:

  1. Widget is created: createState()initState()
  2. Widget is rendered: build()
  3. Parent widget changes data: didUpdateWidget() (optional)
  4. Widget state changes: setState()build()
  5. Widget is removed: deactivate()
  6. Widget is permanently destroyed: dispose()

Console Output for a Typical Interaction:

When the app runs, and you increment the counter by pressing the button, you would see output in the console like this:

If the widget were to be removed from the tree and then reinserted, you would also see:

When to Use These Lifecycle Methods:

  • initState(): Use for one-time initialization (e.g., initializing controllers, fetching data).
  • build(): Use for rendering your UI. This method is called often, so it should be efficient.
  • didUpdateWidget(): Use when you need to handle changes in widget properties or data from the parent.
  • setState(): Use to trigger a rebuild of the widget when its internal state changes.
  • deactivate() and dispose(): Use for cleanup, especially in dispose(), when a widget is permanently removed.

This example provides a clear understanding of the widget lifecycle and where to place different types of logic based on the state of your widget.

warningComments are closed.