[英]How best to use Riverpod to manage items in a list
您可以使用家庭,但在這種情況下,由於您的條目數量不固定,這會使事情變得不必要地復雜化。
這是一個用hooks_riverpod編寫的完整可運行示例。 如果您需要我翻譯為不使用鈎子,我也可以這樣做。 請記住,這是故意簡單且有點幼稚,但應該適應您的情況。
首先,model class。 我通常會使用freezed ,但對於這個問題,這超出了 scope 的范圍。
class Model {
final int id;
final Color color;
Model(this.id, this.color);
}
接下來,StateNotifier:
class ContainerListState extends StateNotifier<List<Model>> {
ContainerListState() : super(const []);
static final provider = StateNotifierProvider<ContainerListState, List<Model>>((ref) {
return ContainerListState();
});
void setAllColor(Color color) {
state = state.map((model) => Model(model.id, color)).toList();
}
void setModelColor(Model model, Color color) {
final id = model.id;
state = state.map((model) {
return model.id == id ? Model(id, color) : model;
}).toList();
}
void addItem() {
// TODO: Replace state.length with your unique ID
state = [...state, Model(state.length, Colors.lightBlue)];
}
}
最后,UI 組件(鈎子):
class MyHomePage extends HookWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final modelList = useProvider(ContainerListState.provider);
return Scaffold(
appBar: AppBar(
title: Text('ListView of Containers'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
context.read(ContainerListState.provider.notifier).addItem();
},
),
],
),
body: ListView.builder(
itemCount: modelList.length,
itemBuilder: (_, index) {
return ContainerWithButton(model: modelList[index]);
},
),
floatingActionButton: RedButton(),
);
}
}
class ContainerWithButton extends StatelessWidget {
const ContainerWithButton({
Key? key,
required this.model,
}) : super(key: key);
final Model model;
@override
Widget build(BuildContext context) {
return ListTile(
tileColor: model.color,
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.lightGreen),
onPressed: () {
context.read(ContainerListState.provider.notifier).setModelColor(model, Colors.purple);
},
child: Text('Button'),
),
);
}
}
class RedButton extends HookWidget {
const RedButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// Bonus: Red button will be notified on changes
final state = useProvider(ContainerListState.provider);
return FloatingActionButton.extended(
onPressed: () {
context.read(ContainerListState.provider.notifier).setAllColor(Colors.orange);
},
backgroundColor: Colors.red,
label: Text('Set all color'),
);
}
}
非鈎子:
class MyHomePage extends ConsumerWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
final modelList = watch(ContainerListState.provider);
return Scaffold(
appBar: AppBar(
title: Text('ListView of Containers'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
context.read(ContainerListState.provider.notifier).addItem();
},
),
],
),
body: ListView.builder(
itemCount: modelList.length,
itemBuilder: (_, index) {
return ContainerWithButton(model: modelList[index]);
},
),
floatingActionButton: RedButton(),
);
}
}
class ContainerWithButton extends StatelessWidget {
const ContainerWithButton({
Key? key,
required this.model,
}) : super(key: key);
final Model model;
@override
Widget build(BuildContext context) {
return ListTile(
tileColor: model.color,
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.lightGreen),
onPressed: () {
context.read(ContainerListState.provider.notifier).setModelColor(model, Colors.purple);
},
child: Text('Button'),
),
);
}
}
class RedButton extends ConsumerWidget {
const RedButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
// Bonus: Red button will be notified on changes
final state = watch(ContainerListState.provider);
return FloatingActionButton.extended(
onPressed: () {
context.read(ContainerListState.provider.notifier).setAllColor(Colors.orange);
},
backgroundColor: Colors.red,
label: Text('Set all color'),
);
}
}
我建議將其放入新的 Flutter 應用程序中進行測試。
Alex 的非 hooks 版本與riverpod有點不同^1.0.0
我更改了與版本無關的一件小事:我將提供程序從 class 移到全局 scope,這兩種方法都有效,官方文檔在下面顯示了這個版本。
class ContainerListState extends StateNotifier<List<Model>> {
ContainerListState() : super(const []);
// No static provider declaration in here
...
}
// Provider moved out here
final containerListProvider = StateNotifierProvider<ContainerListState, List<Model>>((ref) {
return ContainerListState();
});
ProviderScope 是應用程序仍然能夠訪問提供程序所必需的。
void main() {
runApp(const ProviderScope(child: MyApp()));
}
關於這個問題從 0.12 到 1.0 的變化:
StatelessWidget
不再有context.read()
-> 使用ConsumerWidget
WidgetRef ref
和ref.watch()
而不是ScopedReader watch
非鈎子:
帶河莢 ^1.0.4
class MyHomePage extends ConsumerWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final modelList = ref.watch(containerListProvider);
return Scaffold(
appBar: AppBar(
title: Text('ListView of Containers'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
ref.read(containerListProvider.notifier).addItem();
},
),
],
),
body: ListView.builder(
itemCount: modelList.length,
itemBuilder: (_, index) {
return ContainerWithButton(model: modelList[index]);
},
),
floatingActionButton: RedButton(),
);
}
}
class ContainerWithButton extends ConsumerWidget {
const ContainerWithButton({
Key? key,
required this.model,
}) : super(key: key);
final Model model;
@override
Widget build(BuildContext context, WidgetRef ref) {
return ListTile(
tileColor: model.color,
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.lightGreen),
onPressed: () {
ref
.read(containerListProvider.notifier)
.setModelColor(model, Colors.purple);
},
child: Text('Button'),
),
);
}
}
class RedButton extends ConsumerWidget {
const RedButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// Bonus: Red button will be notified on changes
final state = ref.watch(containerListProvider);
return FloatingActionButton.extended(
onPressed: () {
ref.read(containerListProvider.notifier).setAllColor(Colors.orange);
},
backgroundColor: Colors.red,
label: Text('Set all color'),
);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.