К содержимому

Consumers

Consumer — это виджет, который служит связующим звеном между Widget tree и Provider tree.

Единственное существенное отличие Consumer от обычных виджетов заключается в том, что Consumer получает доступ к Ref. Это позволяет ему читать providers и отслеживать их изменения. Подробнее см. Refs.

Consumers представлены в нескольких вариантах, в основном для удобства и личных предпочтений разработчика. Вы можете встретить:

  • Consumer, "builder" виджет (аналогичный FutureBuilder). Он позволяет виджетам взаимодействовать с providers, не наследуясь ни от чего, кроме StatelessWidget или StatefulWidget.
    // Наследуемся от StatelessWidget как обычно
    class MyWidget extends StatelessWidget {

    Widget build(BuildContext context) {
    // Виджет, похожий на FutureBuilder
    return Consumer(
    // Колбэк "builder" предоставляет параметр "ref"
    builder: (context, ref, _) {
    // Через ref можно подписываться на providers
    final value = ref.watch(myProvider);
    return Text(value.toString());
    },
    );
    }
    }
  • ConsumerWidget, разновидность StatelessWidget. Вместо наследования от StatelessWidget, вы наследуетесь от ConsumerWidget. Он ведёт себя так же, за исключением того, что метод build получает дополнительный параметр WidgetRef.
    // Наследуемся от ConsumerWidget вместо StatelessWidget
    class MyWidget extends ConsumerWidget {
    // "build" получает дополнительный параметр

    Widget build(BuildContext context, WidgetRef ref) {
    // Через "ref" можно подписываться на providers
    final value = ref.watch(myProvider);
    return Text(value.toString());
    }
    }
  • ConsumerStatefulWidget, разновидность StatefulWidget.
    Как и в предыдущем случае, вместо наследования от StatefulWidget вы наследуетесь от ConsumerStatefulWidget. А вместо State вы наследуетесь от ConsumerState. Главное отличие заключается в том, что ConsumerState предоставляет свойство ref.
    // Наследуемся от ConsumerStatefulWidget вместо StatefulWidget
    class MyWidget extends ConsumerStatefulWidget {

    ConsumerState<MyWidget> createState() => _MyWidgetState();
    }
    // Наследуемся от ConsumerState вместо State
    class _MyWidgetState extends ConsumerState<MyWidget> {
    // Доступно свойство "ref"

    Widget build(BuildContext context) {
    // Через "ref" можно подписываться на providers
    final value = ref.watch(myProvider);
    return Text(value.toString());
    }
    }
    В качестве альтернативы, вы можете найти дополнительные consumers в пакете hooks_riverpod. Они объединяют consumers Riverpod с flutter_hooks. Если вас не интересуют хуки, вы можете их игнорировать.

Какой вариант использовать?

Выбор consumer в основном зависит от личных предпочтений. Можно использовать Consumer для всего — это более универсальный, но чуть более многословный вариант. Но это разумная цена, если вам не нравится, как Riverpod использует StatelessWidget и StatefulWidget.

Но если у вас нет твердого мнения, мы рекомендуем использовать ConsumerWidget (или ConsumerStatefulWidget если вам нужен State).

Почему мы не можем использовать StatelessWidget + context.watch?

В альтернативных пакетах, таких как provider, можно использовать context.watch чтобы подписываться на providers. Это работает внутри любого виджета, если у вас есть BuildContext. Так почему же в Riverpod это не так?

Причина в том, что полагаться только на BuildContext вместо Ref не позволило бы надёжно реализовать механизм Automatic disposal. Существуют способы сделать реализацию, которая «в большинстве случаев работает» с BuildContext, но проблема в том, что есть множество тонких edge-case’ов, которые могут незаметно ломать auto-dispose.

Это привело бы к утечкам памяти, но это не главная проблема. Automatic disposal ресурсов важнее тем, что оно останавливает выполнение ненужного кода. Если auto-dispose не сработает, provider может продолжать, например, выполнять сетевые запросы в фоне. Поэтому Riverpod предпочёл не жертвовать надёжностью ради небольшого удобства.

примечание

Чтобы смягчить неудобства, связанные с использованием ConsumerWidget/ConsumerStatefulWidget вместо StatelessWidget/StatefulWidget, Riverpod предоставляет различные рефакторинги в IDE, таких как VS Code и Android Studio.

Refactor to Consumer

Чтобы включить их в вашей IDE, см. раздел Getting started