Search code examples
flutterfirebase-realtime-databasedartsetstate

How to Change AppBar 'title:' Value without Re-running FirebaseAnimatedList


I am using FirebaseAnimatedList in a Flutter/Dart chat app. The simplified build() method is as follows:

@override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: AppBar(
          title: Text(_onLineStatus), // <-- This text value changed using setState()
        ),
        body: Column(
          children: <Widget>[
            Flexible(
              child: FirebaseAnimatedList(
                query: reference,
                sort: (a, b) => b.key.compareTo(a.key),
                padding: EdgeInsets.all(8.0),
                reverse: true,
                itemBuilder: (BuildContext context, DataSnapshot snapshot,
                    Animation<double> animation, int index) {
                  return ChatMessage(snapshot: snapshot, animation: animation);
                },
              ),
            ),
            Divider(height: 1.0),
            Container(
              decoration: BoxDecoration(color: Theme.of(context).cardColor),
              child: _buildTextComposer(),
            )
          ],
        ));
  }

I want to change the value of _onLineStatus on line 5 based on an event value returned by a listener, basically to indicate if the other chat participant in on or off line. I want any change to the status to reflect immediately. The obvious way to do this is to use setState() but of course this triggers a full rerun of the build() method which therefore reruns the FirebaseAnimatedList query, downloading the same data once again. I want to avoid this.

All examples of the use of FirebaseAnimatedList show it as part of the build() method yet we are recommended to avoid putting database calls into build() to avoid these side-effects, because build() can be run multiple times.

My questions therefore are:

  1. How can I move the call to FirebaseAnimatedList outside of the build() method so that I can use setState() to update the value of the AppBar title: property WITHOUT it rerunning FirebaseAnimatedList?

OR...

  1. How can I update the value of the AppBar title: property without rerunning the build() method ie. without calling setState()?

Solution

  • Create a StateFullWidget containing your app bar. Something like this:

    Widget build(BuildContext context) {
        return new Scaffold(
            appBar: CustomAppBar(), 
            body: Column(
            ...
    

    And then your new appbar widget:

    class CustomAppBar extends StatefulWidget {
      @override
      _CustomAppBarState createState() => _CustomAppBarState();
    }
    
    class _CustomAppBarState extends State<CustomAppBar> {
      String _onLineStatus = "online";
    
      @override
      Widget build(BuildContext context) {
        return AppBar(
          title: Text(_onLineStatus),
        );
      }
    }
    

    in this way you can independently rebuild the appbar from the list. You need to call setState in your new widget.