Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Widget's didUpdateWidget method called when screen rotates with MaterialApp routes

Tags:

flutter

dart

When I use routes in MaterialApp the child widget's (MyHomePage) didUpdateWidget is called whenever I rotate the screen/open the keyboard etc.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      routes: {
        '/': (_) => MyHomePage(title: 'Flutter Demo Home Page'),
      },
      initialRoute: '/',
    );
  }
}

On the other hand, when I use the home parameter, didUpdateWidget is not called when I rotate the screen/open the keyboard.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

The issue I have is that I am using the Bloc pattern sample as a guide so my Bloc is disposed and recreated whenever the didUpdateWidget is called. This means I lose all my app's state that is in the Bloc, e.g. what is selected.

@override
void didUpdateWidget(ProductSquare oldWidget) {
    super.didUpdateWidget(oldWidget);
    _disposeBloc();
    _createBloc();
}

Why is there a difference is behavior between using routes and home? How can I make routes behave like home and not call didUpdateWidget when the screen is rotated so the bloc is not unnecessarily recreated?

Full app sample without Bloc that rebuilds whenever I rotate the screen.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      routes: {
        '/': (_) => MyHomePage(title: 'Flutter Demo Home Page'),
      },
      initialRoute: '/',
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

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

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

  @override
  void didUpdateWidget(MyHomePage oldWidget) {
    super.didUpdateWidget(oldWidget);

    print('didUpdateWidget');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
like image 861
S.D. Avatar asked Jan 30 '19 23:01

S.D.


People also ask

How do you call didUpdateWidget in flutter?

didUpdateWidget method Null safety key, the framework will update the widget property of this State object to refer to the new widget and then call this method with the previous widget as an argument. Override this method to respond when the widget changes (e.g., to start implicit animations).

Which method calls first flutter?

initState() This is the first method called when the widget is created (after the class constructor, of course.) initState is called once and only once. It must also call super. initState() .

What is Ismounted in flutter?

Mounting is the process of creating the state of a StatefulWidget and attaching it to a BuildContext.


1 Answers

The issue I have is that I am using the Bloc pattern sample as a guide so my Bloc is disposed and recreated whenever the didUpdateWidget is called. This means I lose all my app's state that is in the Bloc, e.g. what is selected.

This is the problem. Don't do that, it is anti-pattern.

Any widgets you make should keep in mind that they can theoretically be updated thousands of time with no change. You're supposed to verify that something changed before performing side-effects.

As such your didUpdateWidget should be as followed:

@override
void didUpdateWidget(ProductSquare oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (widget.product != oldWidget.product) {
    _disposeBloc();
    _createBloc();
  }
}
like image 126
Rémi Rousselet Avatar answered Sep 19 '22 13:09

Rémi Rousselet