Flutter/Riverpod:StateNotificationProvider内的状态更改时UI未更新



当我知道状态正在改变时,我的应用程序的UI不会更新。我使用Riverpod中的watch方法来处理此问题,但除非我进行热重新加载,否则更改不会生效。

我有一个类HabitListStateNotifier,其中包含从列表中添加/删除习惯的方法:

class HabitListStateNotifier extends StateNotifier<List<Habit>> {
HabitListStateNotifier(state) : super(state ?? []);
void startAddNewHabit(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (_) {
return NewHabit();
});
}
void addNewHabit(String title) {
final newHabit = Habit(title: title);
state.add(newHabit);
}
void deleteHabit(String id) {
state.removeWhere((habit) => habit.id == id);
}
}

这里是这个的提供商:

final habitsProvider = StateNotifierProvider(
(ref) => HabitListStateNotifier(
[
Habit(title: 'Example Habit'),
],
),
);

以下是HabitList(UI中不更新的部分(的实现方式:

class HabitList extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final habitList = watch(habitsProvider.state);
/////////////not updating/////////////
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return HabitCard(
habit: habitList[index],
);
},
itemCount: habitList.length,
);
/////////////not updating/////////////
}
}

最后,HabitCard(HabitList由什么组成(:

class HabitCard extends StatelessWidget {
final Habit habit;
HabitCard({@required this.habit});
@override
Widget build(BuildContext context) {
/////////////function in question/////////////
void deleteHabit() {
context.read(habitsProvider).deleteHabit(habit.id);
}
/////////////function in question/////////////
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(devHeight * 0.03),
),
color: Colors.grey[350],
elevation: 3,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
HabitTitle(
title: habit.title,
),
Consumer(
builder: (context, watch, child) => IconButton(
padding: EdgeInsets.all(8),
icon: Icon(Icons.delete),
/////////////function in question/////////////
onPressed: deleteHabit,
/////////////function in question/////////////
),
),
],
),
],
),
);
}
}

当我按下HabitCard中的删除图标时,我知道Habit正在从列表中删除,但更改不会反映在UI中。然而,当我进行热重新加载时,它会像预期的那样消失。我在这里做错了什么?

由于StateNotifierProvider状态是不可变的,您需要使用state =来替换CRUD操作上的数据,这将根据文档触发UI更新。

然后使用state = <newData>分配新数据

添加和删除重写

你需要写你的add&delete像这样:

void addNewHabit(String title) {
state = [ ...state, Habit(title: title)];
}
void deleteHabit(String id) {
state = state.where((Habit habit) => habit.id != id).toList();
}

你需要用一个新的列表来交换你的旧列表,以便Riverpod启动。

更新代码(针对其他人(

虽然您的查询不需要更新数据,但以下是如何进行更新以保留列表的原始排序顺序的示例;

void updateHabit(Habit newHabit) {
List<Habit> newState = [...state];
int index = newState.indexWhere((habit) => habit.id == newHabit.id);
newState[index] = newHabit;
state = newState;
}

我不知道这是否是正确的处理方式,但我想明白了。在HabitListStateNotifier中,对于addNewHabitdeleteHabit,我添加了这行代码:到末尾:state = state;,它完全按照我希望的方式工作。

我过去常常通过在末尾放state = state;来解决这个问题,但现在由于某种原因,可能是flutter或Riverpod更新,它不再工作了。

不管怎样,这就是我现在设法解决的方法。

void addNewHabit(String title) {
List<Habit> _habits = [...state]; 
final newHabit = Habit(title: title);
_habits.add(newHabit);
state = _habits ; 
}

我所理解的解释。当状态等于一个对象时,为了触发消费者重建。state必须等于该对象的一个新值,但更新state对象本身的变量将不起作用。

希望这能帮助到任何人。

最新更新