Привет, ребята, добро пожаловать обратно в мой учебник. В моем предыдущем уроке я познакомил вас с небольшой частью Riverpod. Мы узнали, как использовать глобальные переменные в нашем приложении с помощью Provider. Но есть проблема, мы не можем работать со статическим приложением. Это означает, что для нашего приложения нам нужно, чтобы взаимодействие с пользователем работало хорошо. Но как мы это сделали с помощью Riverpod в данном случае? Не волнуйтесь, Riverpod предоставил нам возможность сделать наше приложение более реактивным. Позвольте мне представить StateProvider и StateNotifier Provider.

Почему мы говорим об обоих только в одной статье? Потому что я думал, что есть аналогичная функция, предоставляемая Riverpod, чтобы сделать наше приложение более интерактивным.

StateProvider — это провайдер, который предоставляет способ изменить свое состояние. Это упрощение StateNotifierProvider, предназначенное для того, чтобы избежать необходимости писать класс StateNotifier для очень простых случаев использования.

Провайдер состояния

На первом уроке мы попробуем, как работает StateProvider. Мы можем управлять нашим простым состоянием, используя StateProvider вместо StateNotifierProvider, как сказано выше в Riverpod. Хорошо, давайте кодировать!

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class StateProviderExample extends ConsumerWidget {
  const StateProviderExample({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'State Provider Example',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.w700,
            color: Colors.white,
          ),
        ),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'State Provider Increment Example',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.w500,
              ),
            ),
            const SizedBox(
              height: 50,
            ),
            const Text(
              '0',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.w700,
              ),
            ),
            const SizedBox(
              height: 20,
            ),
            ElevatedButton(onPressed: () {}, child: const Text('Increment'))
          ],
        ),
      ),
    );
  }
}

Давайте создадим ConsumerWidget. Как я объяснял вам в своем предыдущем уроке, мы можем взаимодействовать с нашим состоянием провайдера, используя ref. Итак, нам нужно получить доступ к ref с помощью ConsumerWidget. Над простым кодом мы попытаемся увеличить наше значение, как мы это делаем?

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// OUR DEFAULT VALUE
final numberProvider = StateProvider<int>((ref) {
  return 0;
});

class StateProviderExample extends ConsumerWidget {
  const StateProviderExample({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // CREATE OUR VALUE
    int numberVal = ref.watch(numberProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'State Provider Example',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.w700,
            color: Colors.white,
          ),
        ),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'State Provider Increment Example',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.w500,
              ),
            ),
            const SizedBox(
              height: 50,
            ),
            Text(
              numberVal.toString(),
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.w700,
              ),
            ),
            const SizedBox(
              height: 20,
            ),
            ElevatedButton(
                onPressed: () {
                  ref.read(numberProvider.notifier).state++;
                },
                child: const Text('Increment'))
          ],
        ),
      ),
    );
  }
}

Я редактировал свой предыдущий код. Итак, я создаю начальное значение типа int, используя StateProvider. Затем объявите это значение в методе BuildContext, используя ref.watch. Делая это, мы создали реактивную стоимость. Итак, наконец, мы просто увеличиваем наше значение, используя ref.read в методе onPressed. Вуаля, наше значение будет меняться каждый раз, когда мы нажимаем на кнопку с повышенным уровнем. Достаточно просто, верно?

Поставщик уведомлений о состоянии

Государственный провайдер достаточно прост, верно? Мы можем сделать наше приложение более интерактивным. Но, к сожалению, StateProvider не рекомендуется для наших сложных приложений.

Вы не должны использовать StateProvider, если:

  • вашему состоянию требуется логика проверки
  • ваше состояние представляет собой сложный объект (например, пользовательский класс, список/карту и т. д.)
  • логика изменения вашего состояния более сложна, чем простая count++.

Итак, как мы управляем взаимодействием с пользователем в наших сложных приложениях? Как я упоминал выше, Riverpod предоставил нам для обработки таких случаев StateNotifier Provider.

StateNotifierProvider — это провайдер, который используется для прослушивания и предоставления StateNotifier (из пакета state_notifier, который реэкспортирует Riverpod).
StateNotifierProvider вместе с StateNotifier — это рекомендуемое решение Riverpod для управления состоянием, которое может изменение реакции на взаимодействие с пользователем.

Это похоже на StateProvider, если вы сомневаетесь в том, что я сказал, давайте кодировать! В этом случае мы попробуем добавить человека. Прежде всего, давайте создадим простой экран для отображения данных человека.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class StateNotifierProviderExample extends ConsumerWidget {
  const StateNotifierProviderExample({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'State Notifier Provider Example',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.w700,
            color: Colors.white,
          ),
        ),
        centerTitle: true,
      ),
      body: Column(
        children: [
          const SizedBox(
            height: 80,
          ),
          const Text(
            'Add Person',
            style: TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.w500,
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          Expanded(
            child: ListView.builder(
              itemCount: 1,
              itemBuilder: (context, index) => Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 24,
                    vertical: 13,
                  ),
                  child: Column(
                    children: const [
                      Text(
                        "Name is ",
                        style: TextStyle(),
                      ),
                      SizedBox(
                        height: 5,
                      ),
                      Text(
                        "Age is ",
                        style: TextStyle(),
                      ),
                      SizedBox(
                        height: 5,
                      ),
                      Text(
                        "Job is ",
                        style: TextStyle(),
                      ),
                    ],
                  )),
            ),
          ),
          const SizedBox(
            height: 40,
          ),
          ElevatedButton(
            onPressed: () {},
            child: const Text('Add Person'),
          ),
          const SizedBox(
            height: 80,
          ),
        ],
      ),
    );
  }
}

Наш экран выглядит так:

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

class PersonModel {
  PersonModel({
    this.name,
    this.age,
    this.job,
    this.address,
  });

  String? name;
  int? age;
  String? job;
  String? address;
}

Затем мы создадим класс StateNotifier человека. В этом классе мы создадим метод добавления человека, который мы сможем использовать позже для добавления человека.

import 'package:futureprovider/state_notifier_provider/model/person_model.dart';
import 'package:riverpod/riverpod.dart';

final personProvider =
    StateNotifierProvider<PersonNotifier, List<PersonModel>>((ref) {
  return PersonNotifier();
});

class PersonNotifier extends StateNotifier<List<PersonModel>> {
  PersonNotifier() : super([]);

  void addPerson(PersonModel personModel) {
    state = [...state, personModel];
  }
}

Выше мы не можем использовать state = state.add(personModel), поэтому мы можем использовать оператор распространения Dart для добавления человека. Достаточно просто, не так ли? Наш StateNotifier уже есть, теперь мы можем использовать его на нашем экране.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:futureprovider/state_notifier_provider/model/person_model.dart';
import 'package:futureprovider/state_notifier_provider/person_notifier.dart';

class StateNotifierProviderExample extends ConsumerWidget {
  const StateNotifierProviderExample({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    List<PersonModel> person = ref.watch(personProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'State Notifier Provider Example',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.w700,
            color: Colors.white,
          ),
        ),
        centerTitle: true,
      ),
      body: Column(
        children: [
          const SizedBox(
            height: 80,
          ),
          const Text(
            'Add Person',
            style: TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.w500,
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          Expanded(
            child: ListView.builder(
              itemCount: person.length,
              itemBuilder: (context, index) => Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 24,
                    vertical: 13,
                  ),
                  child: Column(
                    children: [
                      Text(
                        "Name is ${person[index].name}",
                        style: const TextStyle(),
                      ),
                      const SizedBox(
                        height: 5,
                      ),
                      Text(
                        "Age is ${person[index].age}",
                        style: const TextStyle(),
                      ),
                      const SizedBox(
                        height: 5,
                      ),
                      Text(
                        "Address is ${person[index].address}",
                        style: const TextStyle(),
                      ),
                      const SizedBox(
                        height: 5,
                      ),
                      Text(
                        "Job is ${person[index].job}",
                        style: const TextStyle(),
                      ),
                    ],
                  )),
            ),
          ),
          const SizedBox(
            height: 40,
          ),
          ElevatedButton(
            onPressed: () {
              ref.read(personProvider.notifier).addPerson(
                    PersonModel(
                      name: 'Sherlock',
                      address: '221B Baker Street',
                      age: 27,
                      job: 'Detective Consultant',
                    ),
                  );
            },
            child: const Text('Add Person'),
          ),
          const SizedBox(
            height: 80,
          ),
        ],
      ),
    );
  }
}

Хорошо, наш экран StateNotifier готов, давайте посмотрим, как произойдет волшебство!

Просто нажмите на кнопку, и произойдет волшебство. Потрясающе, верно? Спасибо за чтение, надеюсь, вы понимаете, как работают StateProvider и StateNotifierProvider. Вы можете попробовать с нашим собственным приложением. Спасибо, увидимся в следующих уроках/статьях. Увидимся!