Flutter Riverpod v1.0 — состояние не обновляется с помощью списка StateNotifier

#flutter #riverpod

Вопрос:

Я перешел с RiverPod 0.4x на 1.0 стабильный, и теперь этот StateNotifier больше не обновляет состояние, даже если move() функция вызывается (DebugPrint показывает вызов), когда анимация заканчивается. Это работало в 0.4x, но, очевидно, в улучшенной версии 1.0 RiverPod я не полностью мигрировал.

Чего мне не хватает для RiverPod 1.0 для обновления состояния, когда состояние является списком?

 final animateCoversStateNotifierProvider = StateNotifierProvider.autoDispose<
    AnimateCoversStateNotifier,
    List<CoverAlignment>>((ref) => AnimateCoversStateNotifier());
 
 class AnimateCoversStateNotifier extends StateNotifier<List<CoverAlignment>> {
  AnimateCoversStateNotifier() : super([]);

  void addCover({
    required CoverAlignment alignment,
  }) =>
      state.add(alignment);

  void move({
    required int cover,
    bool? readyToOpen,
    bool? speechBalloonVisible,
    Duration? animatedOpacityDuration,
    bool? removeSpeechBalloonPadding,
  }) {
    debugPrint('move cover called');
    Future.delayed(const Duration(milliseconds: 200), () {
      if (mounted) {
        state[cover].removeSpeechPadding = speechBalloonVisible != true;
        state[cover].speechBalloonOpacity =
            speechBalloonVisible == true ? kMaxSpeechBalloonOpacity : 0.0;
        state[cover].x = CoverAlignment.randomDouble();
        state[cover].y = CoverAlignment.randomDouble();
        state[cover].curve = CoverAlignment.getCurve();
        state[cover].seconds = CoverAlignment.randomSeconds();
        state[cover].degrees = CoverAlignment.randomIntInRangeWithMinimum(
          min: 0,
          max: 45,
        );
        /// This was required to update state using RiverPod 0.4x, but no longer works in 
        /// RiverPod 1.0.
        state = state;
      }
    });
  }
}

 

В теле моего экрана сборки я использую watch для реагирования на изменения уведомителя.

 /// Display covers
final List coverAlignment =
    ref.watch(animateCoversStateNotifierProvider);
 

РЕДАКТИРОВАТЬ: создание замороженного класса, как предлагает Remi в комментариях

 import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';
import 'package:myapp/app/corral/models/cover_alignment_model.dart';

part 'animate_covers.freezed.dart';

class AnimateCovers extends StateNotifier<List<CoverAlignment>>
    with _$AnimateCovers {
  factory AnimateCovers() = _AnimateCovers;

  void addCover({
    required int cover,
    required CoverAlignment alignment,
  }) {
    state.insert(cover, alignment);
  }

  void move({
    required int cover,
    bool? readyToOpen,
    bool? speechBalloonVisible,
    Duration? animatedOpacityDuration,
    bool? removeSpeechBalloonPadding,
  }) {
    /// What do I do here?
  }
}
 

Ответ №1:

Выполнение:

 state = state
 

никогда не должен был работать.

Вы не должны изменять существующее состояние. Предполагается, что вы должны клонировать состояние

Вместо этого сделайте что-то вроде:

 state[cover] = state[cover].copyWith(
  removeSpeechPadding: speechBalloonVisible != true,
  ...
),
 

Вы можете сгенерировать этот copyWith метод с помощью Freezed

Комментарии:

1. Просматриваю замороженный pub.dev/packages/ замороженный Remi. В моем сообщении я добавил свою начальную попытку создания замороженного класса моего класса AnimateCoversStateNotifier. Я не понимаю, как это сделать. Если вы можете предоставить некоторый код, это было бы очень ценно.

2. Реми, все еще застрял на этом. Я пробовал несколько разных вещей, и когда состояние представляет собой список, не похоже, что RiverPod 1.0 уведомляет слушателей об изменениях состояния списка. Даже если бы я мог начать copyWith работать, я не понимаю, как это может привести к тому, что StateNotifier внесет изменения в список.

3. Я нашел обходной путь, поскольку я не могу заставить состояние обновляться в statenotifier. Я использую StatefulBuilder и могу вызвать setState(). В любом случае, не уверен, что это проблема в RiverPod 1.0. Спасибо за всю вашу невероятную работу, Реми.