Flutter Drawer gets rebuilt everytime i open it

Viewed 669

I have been workign on this hours trying to solve why the drawer getting rebuilt everytime i open it. Without any progress, i came here to seek for guidance how can i load it once and rebuild it when i need to?

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Home")),
      drawer: const MyDrawer(),
    );
  }
}


class MyDrawer extends StatelessWidget {
  const MyDrawer();
  @override
  Widget build(BuildContext context) {
    print("Build");
    return Drawer(
      child: ListView(
        padding: EdgeInsets.zero,
        children: <Widget>[
          UserAccountsDrawerHeader(
            accountName: Text("Lisa Simpsons"),
            accountEmail: Text("lisa.simpsons@thesimpsons.com"),
          ),
          Text("Grade A - Student")
        ],
      ),
    );
  }
}
1 Answers

You can try something like this. Widget inside drawer: will always be rebuilt because it is disposed when it is closed. You can just perform a simple checking what widget to return based from its state.

In this example, if state is still null it will fetch the data using FutureBuilder. When it is already fetched, it will directly return the Drawer widget.

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    String grade; // Sample state

    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      drawer: Builder(
        builder: (_) {
          if (grade != null) {
            return MyDrawer(grade);
          }

          return FutureBuilder<String>(
            future: Future<String>.delayed(
              const Duration(seconds: 5),
              () => grade = 'A+',
            ),
            builder: (_, AsyncSnapshot<String> snapshot) {
              print('>>>>>>> snapshot = ${snapshot.data}');
              return MyDrawer(snapshot.data);
            },
          );
        },
      ),
    );
  }
}

class MyDrawer extends StatelessWidget {
  const MyDrawer(this.grade);

  final String grade;

  @override
  Widget build(BuildContext context) {
    print('>>>>>>>>>>>>>>>>>>>> Build');

    return Drawer(
      child: ListView(
        padding: EdgeInsets.zero,
        children: <Widget>[
          const UserAccountsDrawerHeader(
            accountName: Text('Lisa Simpsons'),
            accountEmail: Text('lisa.simpsons@thesimpsons.com'),
          ),
          Text('Grade A - Student${grade == null ? "" : "  >>>>>> ($grade)"}')
        ],
      ),
    );
  }
}

Update: Sample using provider.

class SampleState extends ChangeNotifier {
  SampleState() {
    fetchGrade();
  }

  String _grade;

  String get grade => _grade;

  Future<void> fetchGrade() async {
    print('>>>>>>>>>>>>>>>>>>>> FETCHING GRADE');
    await Future<String>.delayed(const Duration(seconds: 5));
    _grade = 'A+';
    notifyListeners();
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<SampleState>(
      create: (_) => SampleState(),
      builder: (_, __) => Scaffold(
        appBar: AppBar(title: const Text('Home')),
        drawer: MyDrawer(),
      ),
    );
  }
}

class MyDrawer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('>>>>>>>>>>>>>>>>>>>> Build');

    return Drawer(
      child: ListView(
        padding: EdgeInsets.zero,
        children: <Widget>[
          const UserAccountsDrawerHeader(
            accountName: Text('Lisa Simpsons'),
            accountEmail: Text('lisa.simpsons@thesimpsons.com'),
          ),
          Consumer<SampleState>(
            builder: (_, SampleState state, __) {
              print('>>>>>>>>>>>>>>>>>>>> REBUILD');
              final String append =
                  state.grade == null ? '' : '  >>>>>>>>>> (${state.grade})';

              return Text('Grade A - Student$append');
            },
          ),
        ],
      ),
    );
  }
}
Related