颤振 - setState 不更新作为参数传递的子小部件变量



我是 Flutter 的新手,并尝试使用两个有状态小部件,第一个调用build()方法中的第二个,我只想更新从构造函数中的父级传递的子小部件变量。

这是我正在尝试的代码。

父小部件

class Parent extends StatefulWidget {
Parent({Key? key}) : super(key: key);
@override
_ParentState createState() => _ParentState();
}
class _ParentState extends State<Parent> {
List appointments = [];
@override
void initState() {
super.initState();

fetchAppointments();
}
@override
Widget build(BuildContext context) {
return Builder(builder: (BuildContext context) {
return RefreshIndicator(
onRefresh: () async {
_pullRefresh();
},
child: ListView(
children: [
AppointmentsWidget(appointments: appointments)     // <----- I passed the variable in constructor and this one is updating in setState and I want it to update in the child widget too
],
),
),
);
});
}
_pullRefresh() {
fetchAppointments();
}
fetchAppointments() {
setState(() {
// Stuff to do
appointments = ......
......
......
});
}
}

子小部件

class AppointmentsWidget extends StatefulWidget {
var appointments;
AppointmentsWidget({this.appointments});
@override
_AppointmentsWidgetState createState() =>
_AppointmentsWidgetState(appointments: appointments);  // <--- Constructor 1
}
class _AppointmentsWidgetState extends State<AppointmentsWidget> {
var appointments;

_AppointmentsWidgetState({this.appointments});  // <--- Constructor 2
@override
Widget build(BuildContext context) {

return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: appointments.length,
itemBuilder: (BuildContext context, int index) {
return Text(appointments[index].toString());     // <--- This is where I use it
},
);
}
}

我知道构造函数调用一次,但我找不到一种方法来调用构造函数或以某种方式将更新的值传递给构造函数。

非常感谢您的帮助。

您应该使子小部件无状态,因为它的状态(约会)由父小部件处理。当前发生的情况是构造子小部件,其中空列表用作其widget.appointments值。然后,当获取约会时,widget.appointments将重建,但由于子项的状态保持不变,因此不会传递此值(子项的initState不会重新运行)。

class AppointmentsWidget extends StatelessWidget {
final List appointments;
const AppointmentsWidget({Key? key, required this.appointments}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: appointments.length,
itemBuilder: (BuildContext context, int index) {
return Text(appointments[index].toString());     // <--- This is where I use it
},
);
}
}

另外,请查看有关处理状态的颤振文档: https://docs.flutter.dev/development/data-and-backend/state-mgmt/intro

这些还表明,最好保持你的状态很高(在本例中是在父小部件中),并使子小部件使用父小部件的状态来适当地呈现自己。

整流

正如您在注释中提到的,您需要子小部件是有状态的(用于维护其他一些数据的状态)。在这种情况下,您可以简单地摆脱appointments状态变量并改用widget.appointments,当父变量使用新值重建时,它将更新。

class AppointmentsWidget extends StatefulWidget {
var appointments;
AppointmentsWidget({this.appointments});
@override
_AppointmentsWidgetState createState() =>
_AppointmentsWidgetState();  // <--- Constructor 1
}
class _AppointmentsWidgetState extends State<AppointmentsWidget> {
_AppointmentsWidgetState();  // <--- Constructor 2
@override
Widget build(BuildContext context) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.appointments.length,
itemBuilder: (BuildContext context, int index) {
return Text(widget.appointments[index].toString());     // <--- This is where I use it
},
);
}
}

你需要一些 listable 来更新小部件,因为父项和子项的context是不同的。在这种情况下,正确的方法(没有状态管理包)是使用InheritedWidget.

继承的类:

class ExampleInherited extends InheritedWidget {
final Widget child;
final ExampleBloc exampleBloc; // <-- change notifier that can do changes and notify their children
const ExampleInherited({Key? key, required this.child, required this.exampleBloc}) : super(key: key, child: child);
static ExampleInherited? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<ExampleInherited>();
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) => true;
}

ChangeNotifier 类:

class ExampleBloc extends ChangeNotifier {
static final ExampleBloc _exampleBloc  = ExampleBloc._internal();
factory ExampleBloc() {
return _exampleBloc;
}
ExampleBloc._internal();
exampleMethod(){
// here you can do whatever you need (update vars)
notifyListeners(); // <-- this notifies the children that they need to be rebuilded
}
}

然后在父视图中设置此项:

ExampleInherited(
exampleBloc: ExampleBloc(),
child: // content
}

然后在您的孩子看来:

@override
Widget build(BuildContext context) {
ExampleBloc exampleBloc = ExampleInherited.of(context)!.exampleBloc;
return AnimatedBuilder(
animation: exampleBloc,
builder: (context, child) {
return //your content
// this will rebuild every time you call notifyListeners() in your bloc
})
}

最新更新