简体   繁体   中英

Unnecessary rebuilds with flutter_hooks

I'm attempting to use StateNotifier , Provider , flutter_hooks , and functional_widget together.

I'm seeing rebuilds in the widget hierarchy where I am not expecting them. I've setup a simple use case below.

My bloc has a method updateName() which is defined as

  void updateName() {
    var name = this.state.userName + "X";
    updateState(this.state.copyWith(userName: name));
  }

As a test, I call this method when one of the MenuItems' is pressed or when the user taps the Update Name button. My expectation is that when updateName() is pressed and the StateNotifiers state is updated, only the userAccountHeader build function will be called since it is the only one listening to the name via:

var name = useStateValue(bloc, (MenuState s) => s.userName);

However, from my logs I can see that all of the widgets in this tree are being rebuilt.

flutter: menuList.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: menuListItem.build
flutter: userAccountHeader.build
import 'package:apptree_client/components/menu/menu_bloc.dart';
import 'package:apptree_client/hooks/hooks.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';

import 'menu_item_view.dart';
part 'menu.g.dart';

@hwidget
Widget menuDrawer(BuildContext context) {
  var bloc = useMenuBloc();
  return Drawer(child: menuList(context, bloc));
}

@hwidget
Widget userAccountHeader(BuildContext context, MenuBloc bloc) {
  var name = useStateValue(bloc, (MenuState s) => s.userName);

  print("userAccountHeader.build");
  return DrawerHeader(
    child: Column(
      children: [
        Text(name),
        MaterialButton(
          onPressed: () => bloc.updateName(),
          child: Text("Update name"),
        )
      ],
    ),
    decoration: BoxDecoration(
      color: Colors.blue,
    ),
  );
}

@hwidget
Widget menuList(BuildContext context, MenuBloc bloc) {
  var menuItems = useStateValue(bloc, (MenuState s) => s.menuItems);
  print("menuList.build");
  var menuItemsWidgets =
      menuItems.map((item) => menuListItem(context, item, bloc)).toList();

  return ListView(children: [
    userAccountHeader(context, bloc),
    ...menuItemsWidgets,
  ]);
}

@hwidget
Widget menuListItem(BuildContext context, MenuItemView view, MenuBloc bloc) {
  print("menuListItem.build");
  return ListTile(
    title: Text(view.title),
    onTap: () => bloc.updateName(),
  );
}

MenuBloc useMenuBloc() {
  final context = useContext();

  return useMemoized(
        () => MenuBloc(
      config: Provider.of(context, listen: false),
      appSettings: Provider.of(context, listen: false),
    ),
  );
}

R useStateValue<T, R>(StateNotifier<T> notifier, R selector(T value)) {
  // ignore: invalid_use_of_protected_member
  final state = useState<R>(selector(notifier.state));
  useEffect(() {
    return notifier.addListener((s) {
      var newVal = selector(s);
      if (!const DeepCollectionEquality().equals(newVal, state.value)) {
        state.value = newVal;
      }
    });
  }, [notifier]);
  return state.value;
}


You are using the functional_widget functions directly instead of using the generated widgets. So instead of each widget having their own context and be able to rebuild separately you created one big widget just like when you only use functions for parts of a widget instead of widget classes.

To solve it make all the widget function calls start with a capital to use the generated widget instead

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM