flutter 扑动/Riverpod:在StateNotifierProvider内状态更改时UI未更新

x33g5p2x  于 2023-02-09  发布在  Flutter
关注(0)|答案(3)|浏览(278)

当我知道状态正在更改时,我的应用的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/////////////
  }
}

最后是HabitCardHabitList的组成部分):

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中。然而,当我执行热重载时,它如预期的那样消失了。我在这里做错了什么?

dnph8jn4

dnph8jn41#

由于StateNotifierProvider状态是不可变的,您需要使用state =替换CRUD操作上的数据-这将触发UI更新as per docs
然后使用state = <newData>分配新数据

添加和删除重写

你需要像这样写你的adddelete

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;
}
dfty9e19

dfty9e192#

我不知道这是不是正确的处理方式,但我想明白了,在HabitListStateNotifier中,对于addNewHabitdeleteHabit,我添加了这行代码:最后:state = state;而且它完全按照我想要的方式工作。

e3bfsja2

e3bfsja23#

我曾经通过把state = state;放在最后来解决这个问题,但现在由于某种原因,可能是flutter或Riverpod更新,它不再工作了。
不管怎样,这就是我现在设法解决它的方法。

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

我理解的解释。当状态等于一个对象时,为了触发消费者重建。状态必须等于该对象的新值,但更新状态对象本身的变量将不起作用。
希望这对任何人都有帮助。

相关问题