我的状态包含一个用户可以修改的列表,向列表添加新项是可以的,但是当你从列表中删除项时,小部件仍然在执行FamilyProvider
选择器,这会失败,因为它要查找的项已经被删除了。
然而,这似乎只发生在Windows和Chrome的调试版本中。在发布模式下,我无法重现它。在dartpad.dev
上,我也无法重现它。
要重现此问题,请单击任意按钮将其删除,并注意Error: Bad state: No element
。
完整示例:
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends ConsumerWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
Widget build(BuildContext context, WidgetRef ref) {
final buttons = ref.watch(appStateProvider).buttons;
print('Rebuild HomePage with $buttons');
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Click on any of the buttons to remove the widget'),
for (final btn in buttons) _ButtonWidget(id: btn.id),
],
),
),
);
}
}
class _ButtonWidget extends ConsumerWidget {
final int id;
_ButtonWidget({
required this.id,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
print('Rebuild ButtonWidget $id');
// this one is still being executed, even if the widget is removed.
final buttonState = ref.watch(buttonStateFamilyProvider(id));
return ElevatedButton(
onPressed: () {
final appStateController = ref.read(appStateProvider.notifier);
final newList = appStateController.state.buttons.toList()
..removeWhere((btn) => btn.id == id);
appStateController.state = AppState(newList);
},
style: ElevatedButton.styleFrom(backgroundColor: Colors.blueGrey),
child: Text(buttonState.name),
);
}
}
final appStateProvider = StateProvider<AppState>((ref) {
return const AppState([
ButtonState(1, 'Button 1'),
ButtonState(2, 'Button 2'),
]);
});
final buttonStateFamilyProvider = Provider.family.autoDispose<ButtonState, int>(
(ref, id) {
ref.onCancel(() {
print('cancelled buttonStateFamilyProvider($id)');
});
print('Executing buttonStateFamilyProvider($id)');
final result = ref.watch(
appStateProvider.select(
(state) => state.buttons.firstWhere(
(btn) => btn.id == id,
),
),
);
print('buttonStateFamilyProvider($id) = $result');
return result;
},
);
class AppState with EquatableMixin {
final List<ButtonState> buttons;
const AppState(this.buttons);
@override
List<Object?> get props => [buttons];
}
class ButtonState with EquatableMixin {
final String name;
final int id;
const ButtonState(this.id, this.name);
@override
List<Object?> get props => [name];
}
pubspec.yaml
name: riverpod_widget_rebuild
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=2.18.5 <3.0.0'
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.3.0
cupertino_icons: ^1.0.2
equatable: ^2.0.5
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
uses-material-design: true
1条答案
按热度按时间rxztt3cl1#
正如雷米所建议的:你可以作弊:
如果在删除ID时重新生成提供程序,则不会引发此错误。
或者,您可以使提供程序可为空。
在小部件中添加'!',因为它不能为空。