【问题标题】:Unnecessary rebuilds with flutter_hooks使用 flutter_hooks 进行不必要的重建
【发布时间】:2020-10-23 23:18:41
【问题描述】:

我正在尝试同时使用 StateNotifierProviderflutter_hooksfunctional_widget

我在小部件层次结构中看到了我没想到的重建。我在下面设置了一个简单的用例。

我的集团有一个方法updateName(),它被定义为

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

作为测试,我在按下 MenuItems 之一或当用户点击 Update Name 按钮时调用此方法。我的期望是,当按下updateName() 并更新StateNotifiers state 时,只会调用userAccountHeader 构建函数,因为它是唯一通过以下方式监听名称的函数:

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

但是,从我的日志中,我可以看到这棵树中的所有小部件都在重建。

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;
}


【问题讨论】:

    标签: flutter provider flutter-hooks flutter-functional-widget


    【解决方案1】:

    您正在直接使用functional_widget 函数,而不是使用生成的小部件。 因此,不是每个小部件都有自己的上下文并且能够单独重建,而是创建了一个大的小部件,就像您只对小部件的一部分而不是小部件类使用函数一样。

    为了解决这个问题,让所有小部件函数调用都以大写开头,以使用生成的小部件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-04
      • 1970-01-01
      • 1970-01-01
      • 2013-06-15
      • 1970-01-01
      • 2013-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多