如何最好地使用 Riverpod 来管理列表中的项目
How best to use Riverpod to manage items in a list
我正在努力弄清楚如何在以下情况下使用 Riverpod。
我有一个 ListView,其中子项是容器,里面有一个按钮。
当按钮被按下时,我想改变那个容器的颜色。我希望使用 Riverpod 提供程序将该颜色存储在一个状态中。
列表外还有一个按钮。当按下时,它应该改变所有容器的颜色。
感觉每个容器都需要一个Change/StateNotifierProvider。我为此使用家庭吗?我如何将特定的状态与其关联的容器关联起来?
红色按钮如何访问所有状态以更改所有状态的颜色?
作为奖励,我还希望红色按钮在其中一个绿色按钮更改其容器颜色时得到通知
非常感谢
您可以使用 family,但在这种情况下,由于您的条目数量不固定,这会使事情变得不必要地复杂化。
这是一个用 hooks_riverpod 编写的完整可运行示例。如果您需要我翻译为不使用钩子,我也可以这样做。请记住,这是故意简单且有点天真,但应该适应您的情况。
首先,模型 class。我通常会使用 freezed 但这超出了这个问题的范围。
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 应用程序中进行测试。
我正在努力弄清楚如何在以下情况下使用 Riverpod。
我有一个 ListView,其中子项是容器,里面有一个按钮。
当按钮被按下时,我想改变那个容器的颜色。我希望使用 Riverpod 提供程序将该颜色存储在一个状态中。
列表外还有一个按钮。当按下时,它应该改变所有容器的颜色。
感觉每个容器都需要一个Change/StateNotifierProvider。我为此使用家庭吗?我如何将特定的状态与其关联的容器关联起来?
红色按钮如何访问所有状态以更改所有状态的颜色?
作为奖励,我还希望红色按钮在其中一个绿色按钮更改其容器颜色时得到通知
非常感谢
您可以使用 family,但在这种情况下,由于您的条目数量不固定,这会使事情变得不必要地复杂化。
这是一个用 hooks_riverpod 编写的完整可运行示例。如果您需要我翻译为不使用钩子,我也可以这样做。请记住,这是故意简单且有点天真,但应该适应您的情况。
首先,模型 class。我通常会使用 freezed 但这超出了这个问题的范围。
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 应用程序中进行测试。