Menu
CoddyTech

Provider: Consumer

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

Здесь провайдер создаётся внутри собственного build у MyApp, а тот же build сразу под ним запрашивает лампу. Приложение выдаёт ошибку: context принадлежит MyApp, который находится выше провайдера, а виджет может найти только провайдеры, расположенные выше него.

Это исправляет Consumer. Это виджет, поэтому он находится ниже провайдера, а его builder получает новый context и саму модель:

Consumer<Lamp>(
  builder: (context, lamp, child) {
    return Text(lamp.isOn ? 'On' : 'Off');
  },
)

Функция builder запускается снова каждый раз, когда лампа вызывает notifyListeners(), подобно виджету, который за ней следит. Внутри неё можно напрямую вызывать методы модели у lamp: onPressed: () => lamp.toggle().

Consumer также перестраивает только обёрнутую им часть, поэтому, если обернуть изменяющуюся часть, остальная часть экрана останется без изменений. В большинстве приложений вы будете использовать context.watch в отдельном виджете, а к Consumer обращаться, когда находитесь в том же build, что и провайдер.

challenge icon

Задание

Средне

Приложение открывается с ошибкой. Помести части лампы внутрь Consumer:

  • Оберни Column в Consumer<Lamp> и верни Column из его builder.
  • Внутри используй lamp из builder для значка, текста и кнопки.

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

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

class Lamp extends ChangeNotifier {
  bool _isOn = false;

  bool get isOn => _isOn;

  void toggle() {
    _isOn = !_isOn;
    notifyListeners();
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Lamp(),
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          appBar: AppBar(title: const Text('Lamp')),
          body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Icon(
                  context.watch<Lamp>().isOn ? Icons.lightbulb : Icons.lightbulb_outline,
                  size: 96,
                  color: context.watch<Lamp>().isOn ? Colors.amber : Colors.grey,
                ),
                Text(context.watch<Lamp>().isOn ? 'The lamp is on' : 'The lamp is off'),
                const SizedBox(height: 16),
                ElevatedButton(
                  onPressed: () => context.read<Lamp>().toggle(),
                  child: const Text('Switch'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
quiz iconПроверьте себя

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

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

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