我正在尝试从父小部件更新通知程序值,而 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,
),
),
);
}
}
谁能帮我解决这个问题。
提前致谢
最佳答案
虽然共享的代码仍然不足以完全重现您的情况,但我可以提供一些建议。
StatefulWidgets
的 state
部分默认是私有(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
,则应在其他地方声明该函数。
综上所述,除非您需要 setState
、initState
或其他生命周期函数,否则您不需要 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/