Menu
CoddyTech

Provider: делимся моделью

Часть раздела Управление состоянием путешествия по Flutter на Coddy. Урок 9 из 27.

Поднятие состояния вверх работает, пока виджеты находятся рядом. Когда значение нужно по всему приложению — на двух экранах, в верхней панели, глубоко внутри списка, — его пришлось бы передавать через каждый промежуточный виджет. Provider позволяет этого избежать. Это пакет: набор кода, который вы подключаете с помощью import 'package:provider/provider.dart';.

Он состоит из трёх частей. Во-первых, модель: класс, который хранит данные и extends ChangeNotifier. Его методы изменяют данные, а затем вызывают notifyListeners():

class CupCounter extends ChangeNotifier {
  int _cups = 0;
  int get cups => _cups;

  void addCup() {
    _cups++;
    notifyListeners();
  }
}

Во-вторых, ChangeNotifierProvider высоко в дереве один раз создаёт модель и передаёт её каждому виджету ниже:

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CupCounter(),
      child: const MyApp(),
    ),
  );
}

В-третьих, любой виджет ниже запрашивает её: context.watch<CupCounter>(), чтобы отобразить её, context.read<CupCounter>(), чтобы вызвать метод. Заголовок и кнопка ниже получают один и тот же счётчик, и ни одному из них ничего не передаётся.

challenge icon

Задание

Средне

Открой приложение: появится ошибка, потому что заголовок запрашивает CupCounter, а выше его никто не предоставляет.

  • В main оберни MyApp в ChangeNotifierProvider, который создаёт CupCounter.

Попробуйте сами

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

class CupCounter extends ChangeNotifier {
  int _cups = 0;

  int get cups => _cups;

  void addCup() {
    _cups++;
    notifyListeners();
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const CupsTitle()),
      body: const Center(child: AddCupButton()),
    );
  }
}

class CupsTitle extends StatelessWidget {
  const CupsTitle({super.key});

  @override
  Widget build(BuildContext context) {
    final counter = context.watch<CupCounter>();
    return Text('Cups: ${counter.cups}');
  }
}

class AddCupButton extends StatelessWidget {
  const AddCupButton({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        context.read<CupCounter>().addCup();
      },
      child: const Text('Another cup'),
    );
  }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Управление состоянием

Потренируйтесь самостоятельно: Онлайн-компилятор Flutter