flutter - 更新通知程序值后未调用 ValueListenableBuilder 构建器方法

标签 flutter dart

我正在尝试从父小部件更新通知程序值,而 ValueListenableBuilder 是在子小部件中定义的,但构建器在更改值后未调用。

这是父部件代码,其中我将两个子部件声明为 StatefulWidget 并且还声明了一个 Notifier 类的静态对象。我正在从 secondChild() 小部件调用方法 updateMenuItemList 像这样 HotKeysWidget.of(context)!.updateMenuItemList(currentCat!['items']); 更新 firstChild() 小部件的列表:

class HotKeysWidget extends StatefulWidget {
  static HotKeysWidgetState? of(BuildContext context) =>
      context.findAncestorStateOfType<HotKeysWidgetState>();

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return HotKeysWidgetState();
  }
}

class HotKeysWidgetState extends State<HotKeysWidget> {
static DealsNotifier appValueNotifier = DealsNotifier();

updateMenuItemList(List<Food> list) {
    appValueNotifier.updateMenuList(list);
}

 @override
  Widget build(BuildContext context) {
  return Container(child: Column(children: [
  firstChild(),
  secondChild(),
  ],
  ),
  );
  
}

}

这是我的通知程序类:

class DealsNotifier {
  ValueNotifier<List<Food>> dealList = ValueNotifier([]);
  ValueNotifier<List<Food>> menuitemList = ValueNotifier([]);
  ValueNotifier<List<Map<String,dynamic>>> categoryList = ValueNotifier([]);

  void updateDealsList(List<Food> list) {
    dealList.value = list;
    print('DEAL LIST IN CLASS: ${dealList}');
  }

  void updateMenuList(List<Food> list) {
    menuitemList.value = list;
    print('PRICE CHANGE: ${menuitemList.value[2].price}');
    print('MENU ITEM LIST IN CLASS: ${menuitemList}');
  }

  void updateCategoryList(List<Map<String,dynamic>> catList) {
    categoryList.value = catList;
    print('DEAL LIST IN CLASS: ${categoryList}');
  }
  List<Food> getDealList() {
    return dealList.value;
  }

  List<Food> getMenuitemList() {
    return menuitemList.value;
  }

  List<Map<String,dynamic>> getCategoryList() {
    return categoryList.value;
  }
}

这是父代码中名为firstChild() 的子控件。这里声明了 ValueListenerBuilder:

class firstChild extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return firstChildState();
  }

}

class firstChildState extends State<firstChild> {

@override
  Widget build(BuildContext context) {
  return ValueListenableBuilder(
    valueListenable: HotKeysWidgetState.appValueNotifier.menuitemList,
builder: (context, List<Food> value, widget)
{
   print('MENUITEM LIST UPDATED: ${value}');
   return HotkeysMenuItemsWidget(
   key: menuItemsKey,
   currentMenu:currentCat != null ? value : [],
   );
},
);

}
}

class secondChild extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return secondChildState();
  }

}

class secondChildState extends State<secondChild> {

@override
  Widget build(BuildContext context) {
  return RaisedButton(
                    
                    onPressed: (){
                    HotKeysWidget.of(context)!.updateMenuItemList([]);
                    },
                    child: Text(
                      'UPDATE',
                      maxLines: 2,
                      textAlign: TextAlign.center,
                      style: const TextStyle(
                        fontSize: 12,
                      ),
                    ),
                  );

}
}

谁能帮我解决这个问题。

提前致谢

最佳答案

虽然共享的代码仍然不足以完全重现您的情况,但我可以提供一些建议。

StatefulWidgetsstate 部分默认是私有(private)的,这是有原因的。您不应该公开它们只是为了访问内部的变量,还有其他几个变量可以访问小部件内的外部类。

所以任何时候你做这样的事情

class firstChild extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return firstChildState();
  }
}

class firstChildState extends State<firstChild> {
  @override
...

只要坚持 StatefulWidget 的默认语法,类也应该在 UpperCamelCase 中首字母大写。

class FirstChild extends StatefulWidget {
  const FirstChild({Key? key}) : super(key: key);

  @override
  State<FirstChild> createState() => _FirstChildState();
}

class _FirstChildState extends State<FirstChild> {
  @override
  Widget build(BuildContext context) {
...

如果您发现自己想要编辑此默认语法,这表明您需要找到更好的方法来实现您正在尝试做的任何事情。如果您需要从 Widget 外部访问在 Widget 中声明的 function,则应在其他地方声明该函数。

综上所述,除非您需要 setStateinitState 或其他生命周期函数,否则您不需要 StatefulWidget首先。所有这些类都可以是Stateless

在没有完整的状态管理解决方案的情况下使 DealsNotifier 类全局可访问的一种简单方法是将其设为 static 类。


class DealsNotifier {
  static ValueNotifier<List<Food>> dealList = ValueNotifier([]);
  static ValueNotifier<List<Food>> menuitemList = ValueNotifier([]);
  static ValueNotifier<List<Map<String, dynamic>>> categoryList =
      ValueNotifier([]);

  static void updateDealsList(List<Food> list) {
    dealList.value = list;
    print('DEAL LIST IN CLASS: ${dealList}');
  }

  static void updateMenuList(List<Food> list) {
    menuitemList.value = list;
    print('PRICE CHANGE: ${menuitemList.value[2].price}');
    print('MENU ITEM LIST IN CLASS: ${menuitemList}');
  }

  static void updateCategoryList(List<Map<String, dynamic>> catList) {
    categoryList.value = catList;
    print('DEAL LIST IN CLASS: ${categoryList}');
  }

  static List<Food> getDealList() {
    return dealList.value;
  }

  static List<Food> getMenuitemList() {
    return menuitemList.value;
  }

  static List<Map<String, dynamic>> getCategoryList() {
    return categoryList.value;
  }
}

然后,当您需要传入 valueListenable 时,您可以通过 DealsNotifier.menuitemlist 访问,它始终是同一个实例。

return ValueListenableBuilder(
      valueListenable: DealsNotifier.menuitemList,
      builder: (context, List<Food> value, widget) {
        print('MENUITEM LIST UPDATED: ${value}');
        return HotkeysMenuItemsWidget(
          key: menuItemsKey,
          currentMenu: currentCat != null ? value : [],
        );
      },
    );

这是所有这些类的 Stateless 版本,在任何需要 UI 更新的地方,您都可以使用 ValueListenableBuilder 并传入 DealsNotifier.whicheverVariableYouWantToListenTo valueListenable。然后调用 DealsNotifier 类中的任何相关方法,即。 DealsNotifier.updateMenuList([])

并且您没有共享您的 HotkeysMenuItemsWidget,但如果您希望在此处查看 UI 中的更改,那么应该在此处显示 ValueListenableBuilder。它目前在小部件树中的位置太高,它需要做的就是重新呈现该 Widget 中的列表,您不需要/想要整个重新构建 HotkeysMenuItemsWidget 来自父小部件。


class FirstChild extends StatelessWidget {
  const FirstChild({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder( // this should be inside HotkeysMenuItemsWidget
      valueListenable: DealsNotifier.menuitemList,
      builder: (context, List<Food> value, widget) {
        print('MENUITEM LIST UPDATED: ${value}');
        return HotkeysMenuItemsWidget(
          key: menuItemsKey,
          currentMenu: currentCat != null ? value : [],
        );
      },
    );
  }
}

class SecondChild extends StatelessWidget {
  const SecondChild({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        DealsNotifier.updateMenuList([]); 
      },
      child: Text(
        'UPDATE',
        maxLines: 2,
        textAlign: TextAlign.center,
        style: const TextStyle(
          fontSize: 12,
        ),
      ),
    );
  }
}

class HotKeysWidget extends StatelessWidget {
  const HotKeysWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          FirstChild(),
          SecondChild(),
        ],
      ),
    );
  }
}

关于flutter - 更新通知程序值后未调用 ValueListenableBuilder 构建器方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72585555/

相关文章:

webview - 如何在 Flutter 项目中指定 dart Uri 的编码

flutter - 如何通过另一个类的方法设置状态

dart - 如何在 Flutter App 中管理选项卡之间的状态

flutter - 如何使变量成为最终变量并在 initState() 中为其赋值

dart - 如何将映射中的数组转换为字符串数组

flutter - 从一个 Dart 类访问另一个 Dart 类的功能

firebase - 应用程序检查 Firebase 可调用函数上不必要的强制执行

flutter - 拜托,如何将蓝色容器嵌入代码中

android - Flutter Google Maps Android构建失败

flutter - UI 在渲染前不等待值