Menu
CoddyTech

Provider:共享一个模型

本课属于 Coddy Flutter 学习旅程的“状态管理”单元。第 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 中,用会创建 CupCounter 的 ChangeNotifierProvider 包裹 MyApp。

亲手试试

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 在线编译器