Flutter / Riverpod: пользовательский интерфейс не обновляется при изменении состояния в StateNotifierProvider

Пользовательский интерфейс моего приложения не обновляется, когда я точно знаю, что состояние меняется. Я использую метод watch от Riverpod, чтобы справиться с этим, но изменения не вступят в силу, если я не сделаю горячую перезагрузку.

У меня есть класс 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 (часть пользовательского интерфейса, которая не обновляется):

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 удаляется из списка, но это изменение не отражается в пользовательском интерфейсе. Однако, когда я делаю горячую перезагрузку, она исчезает, как и ожидалось. Что я здесь делаю не так?


person wolfeweeks    schedule 28.12.2020    source источник
comment
так же, как вы уже выяснили в своем комментарии, вам нужно обновить состояние, чтобы принудительно обновить, в вашем случае, потому что вы просто добавляете / удаляете новый объект в список, он не будет обновляться, если вы не сделаете что-то вроде это состояние = state.add (newHabit); это также происходит с ValueNotifier, потому что это тот же объект, который изменяется, а не новый   -  person EdwynZN    schedule 29.12.2020


Ответы (1)


Я не знаю, правильный ли это способ справляться с проблемами, но я понял это. В HabitListStateNotifier для addNewHabit и deleteHabit я добавил эту строку кода: в конец: state = state;, и она работает именно так, как я хочу.

person wolfeweeks    schedule 28.12.2020