Flutter StatefulWidget 未重建
Flutter StatefulWidget is not being rebuild
我在使用这段代码时遇到了一些问题..
我将我的小部件“ComponentsHistoriqueDeployment”移动到带有 initState() 的有状态小部件,以解决每次小部件重建时焦点的一些问题。
所以实际上数据是第一次获取,但当我在搜索栏“Sélectionnez le composant”中添加内容或更改 datePicker 时,它不会改变。
我不明白为什么...
这是父级:
class HistoriquePage extends StatefulWidget {
final String pageName;
final String namespace;
const HistoriquePage({Key? key, required this.pageName, required this.namespace}) : super(key: key);
@override
_HistoriquePageState createState() => _HistoriquePageState();
}
class _HistoriquePageState extends State<HistoriquePage> {
final _debounce = Debounce();
DateTimeRange? dateRange;
String searchedValue = "";
Post? user;
void _sendSearch(String value) {
_debounce.run(() {
setState(() {
searchedValue = value;
});
});
}
@override
Widget build(BuildContext context) => GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
appBar: AppBar(
title: Text(widget.pageName),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: DateRangeField(
enabled: true,
firstDate: new DateTime(2020),
helpText: 'Sélectionnez un interval de dates',
fieldStartLabelText: 'Date de début',
fieldEndLabelText: 'Date de fin',
fieldStartHintText: 'Début',
fieldEndHintText: 'Fin',
dateFormat: DateFormat('dd/MM/yyyy'),
saveText: 'OK',
decoration: InputDecoration(
prefixIcon: Icon(Icons.date_range, color: Theme.of(context).primaryColor),
hintText: 'Sélectionnez un intervalle de dates',
hintStyle: Theme.of(context).textTheme.headline6,
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
dateRange = value!;
});
}),
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.search, color: Theme.of(context).primaryColor),
border: OutlineInputBorder(),
labelText: 'Sélectionnez le composant',
labelStyle: Theme.of(context).textTheme.headline6),
onChanged: _sendSearch),
),
Container(height: MediaQuery.of(context).size.height - 150, child: ComponentsHistoriqueDeployment(searchedValue, dateRange: dateRange))
],
),
),
));
}
以及应该重建的小部件:
class ComponentsHistoriqueDeployment extends StatefulWidget {
ComponentsHistoriqueDeployment(this.searchedValue, {this.dateRange, Key? key}) : super(key: key);
final String searchedValue;
final DateTimeRange? dateRange;
@override
ComponentsHistoriqueDeploymentState createState() => ComponentsHistoriqueDeploymentState();
}
class ComponentsHistoriqueDeploymentState extends State<ComponentsHistoriqueDeployment> {
List<User>? listOfGroups;
@override
void initState() {
getGroupsList();
super.initState();
}
getGroupsList() async {
listOfGroups = await HistoriqueService.fetchHistorique(widget.searchedValue, dateRange: widget.dateRange);
setState(() {
listOfGroups = listOfGroups;
});
}
@override
Widget build(BuildContext context) {
return listOfGroups == null
? Center(child: CircularProgressIndicator())
: ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemCount: listOfGroups!.length,
itemBuilder: (context, index) {
return Card(
child: Column(children: [
Padding(
padding: const EdgeInsets.only(top: 8),
child: Badge(
toAnimate: true,
animationDuration: Duration(seconds: 2),
shape: BadgeShape.square,
badgeColor: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(8),
badgeContent: Text(listOfGroups![index].name, style: TextStyle(color: Specific.getWhite, fontSize: 16)),
),
),
_displayMoreInformationOnComponent(listOfGroups, index, context)
]),
);
});
}
Widget _displayMoreInformationOnComponent(result, index, context) {
return Container(
child: ListTile(
title: Text('Tag: ' + result[index].username),
subtitle: Text('Date: ' + result[index].address.street),
leading: Icon(Icons.label),
trailing: Wrap(
spacing: 20,
children: <Widget>[
IconButton(
icon: Icon(Icons.help),
onPressed: () => Dialogs.bottomMaterialDialog(
msgStyle: TextStyle(color: Theme.of(context).textTheme.bodyText2?.color),
msg: 'Tag: ' +
result[index].name +
'\nStatus: ' +
result[index].name +
'\nDernier déploiement: ' +
result[index].name +
'\nType de route: ' +
result[index].name +
'\nDernier commit par: ' +
result[index].name +
'\n',
title: result[index].name,
color: Specific.getOrange,
context: context,
actions: [
IconsButton(
text: "OK",
iconData: Icons.check_circle,
color: Colors.green,
textStyle: TextStyle(color: Specific.getWhite),
iconColor: Specific.getWhite,
onPressed: () {
Navigator.of(context).pop();
},
),
]),
),
],
),
),
);
}
}
这是预期的行为:initState()
仅在小部件初始化期间调用一次。即使属性更改了它们的值,也不会重新创建 State
对象,因此不会调用 getGroupsList()
。
在这种情况下,我建议您将 getGroupsList()
移至 _HistoriquePageState
小部件,并在搜索值或日期范围更改时调用它。然后,不是将 searchedValue
和 dateRange
属性传递给 ComponentsHistoriqueDeployment
,而是传递 listOfGroups
值。
这样,您可以确保每次调用 getGroupsList()
以及更新 UI。
我在使用这段代码时遇到了一些问题.. 我将我的小部件“ComponentsHistoriqueDeployment”移动到带有 initState() 的有状态小部件,以解决每次小部件重建时焦点的一些问题。 所以实际上数据是第一次获取,但当我在搜索栏“Sélectionnez le composant”中添加内容或更改 datePicker 时,它不会改变。
我不明白为什么...
这是父级:
class HistoriquePage extends StatefulWidget {
final String pageName;
final String namespace;
const HistoriquePage({Key? key, required this.pageName, required this.namespace}) : super(key: key);
@override
_HistoriquePageState createState() => _HistoriquePageState();
}
class _HistoriquePageState extends State<HistoriquePage> {
final _debounce = Debounce();
DateTimeRange? dateRange;
String searchedValue = "";
Post? user;
void _sendSearch(String value) {
_debounce.run(() {
setState(() {
searchedValue = value;
});
});
}
@override
Widget build(BuildContext context) => GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
appBar: AppBar(
title: Text(widget.pageName),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: DateRangeField(
enabled: true,
firstDate: new DateTime(2020),
helpText: 'Sélectionnez un interval de dates',
fieldStartLabelText: 'Date de début',
fieldEndLabelText: 'Date de fin',
fieldStartHintText: 'Début',
fieldEndHintText: 'Fin',
dateFormat: DateFormat('dd/MM/yyyy'),
saveText: 'OK',
decoration: InputDecoration(
prefixIcon: Icon(Icons.date_range, color: Theme.of(context).primaryColor),
hintText: 'Sélectionnez un intervalle de dates',
hintStyle: Theme.of(context).textTheme.headline6,
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
dateRange = value!;
});
}),
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.search, color: Theme.of(context).primaryColor),
border: OutlineInputBorder(),
labelText: 'Sélectionnez le composant',
labelStyle: Theme.of(context).textTheme.headline6),
onChanged: _sendSearch),
),
Container(height: MediaQuery.of(context).size.height - 150, child: ComponentsHistoriqueDeployment(searchedValue, dateRange: dateRange))
],
),
),
));
}
以及应该重建的小部件:
class ComponentsHistoriqueDeployment extends StatefulWidget {
ComponentsHistoriqueDeployment(this.searchedValue, {this.dateRange, Key? key}) : super(key: key);
final String searchedValue;
final DateTimeRange? dateRange;
@override
ComponentsHistoriqueDeploymentState createState() => ComponentsHistoriqueDeploymentState();
}
class ComponentsHistoriqueDeploymentState extends State<ComponentsHistoriqueDeployment> {
List<User>? listOfGroups;
@override
void initState() {
getGroupsList();
super.initState();
}
getGroupsList() async {
listOfGroups = await HistoriqueService.fetchHistorique(widget.searchedValue, dateRange: widget.dateRange);
setState(() {
listOfGroups = listOfGroups;
});
}
@override
Widget build(BuildContext context) {
return listOfGroups == null
? Center(child: CircularProgressIndicator())
: ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemCount: listOfGroups!.length,
itemBuilder: (context, index) {
return Card(
child: Column(children: [
Padding(
padding: const EdgeInsets.only(top: 8),
child: Badge(
toAnimate: true,
animationDuration: Duration(seconds: 2),
shape: BadgeShape.square,
badgeColor: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(8),
badgeContent: Text(listOfGroups![index].name, style: TextStyle(color: Specific.getWhite, fontSize: 16)),
),
),
_displayMoreInformationOnComponent(listOfGroups, index, context)
]),
);
});
}
Widget _displayMoreInformationOnComponent(result, index, context) {
return Container(
child: ListTile(
title: Text('Tag: ' + result[index].username),
subtitle: Text('Date: ' + result[index].address.street),
leading: Icon(Icons.label),
trailing: Wrap(
spacing: 20,
children: <Widget>[
IconButton(
icon: Icon(Icons.help),
onPressed: () => Dialogs.bottomMaterialDialog(
msgStyle: TextStyle(color: Theme.of(context).textTheme.bodyText2?.color),
msg: 'Tag: ' +
result[index].name +
'\nStatus: ' +
result[index].name +
'\nDernier déploiement: ' +
result[index].name +
'\nType de route: ' +
result[index].name +
'\nDernier commit par: ' +
result[index].name +
'\n',
title: result[index].name,
color: Specific.getOrange,
context: context,
actions: [
IconsButton(
text: "OK",
iconData: Icons.check_circle,
color: Colors.green,
textStyle: TextStyle(color: Specific.getWhite),
iconColor: Specific.getWhite,
onPressed: () {
Navigator.of(context).pop();
},
),
]),
),
],
),
),
);
}
}
这是预期的行为:initState()
仅在小部件初始化期间调用一次。即使属性更改了它们的值,也不会重新创建 State
对象,因此不会调用 getGroupsList()
。
在这种情况下,我建议您将 getGroupsList()
移至 _HistoriquePageState
小部件,并在搜索值或日期范围更改时调用它。然后,不是将 searchedValue
和 dateRange
属性传递给 ComponentsHistoriqueDeployment
,而是传递 listOfGroups
值。
这样,您可以确保每次调用 getGroupsList()
以及更新 UI。