【Flutter】状态管理provider(一)基本使用

299 阅读2分钟

前言

setState调用这个方法会导致整个页面重绘,如果页面比较复杂,可以使用官方推荐的provider包。它允许通过一个中心组件来传递和共享数据。它使用了InheritedWidget,建立了一个数据传递的上下文树来实现数据共享。

Provider

常见类型:

  • MultiProvider:用于在一个组件中共享多个不同类型的Provider。它可以简化在一个组件中使用多个Provider的情况。

除了这些内置的Provider类型,Provider还提供了一些辅助类和功能,以便更好地组织和管理共享数据。例如:

  • Provider.of:用于从Provider中获取共享数据。
  • Provider.listen:用于监听共享数据的变化。
  • Consumer和Selector:用于在UI中订阅共享数据的变化,并更新相应的UI。

安装

添加依赖,命令安装

flutter pub add provider

或者在pubspec.yaml中添加

dependencies: provider: ^6.1.2

用法

1、注册provider提供数据

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

不建议在程序入口使用Provider,可在指定页面使用。 可以使用 MultiProvider 来同时提供多个 Providers

void main() {
  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (context) => CounterProvider()),
      ChangeNotifierProvider(create: (context) => CounteModel())],
    child: const MyProvider(),
  ));
}

另外当按照官方推荐写法时报错:

Provider(
  create: (_) => MyModel(),
  child: ...
)

4394db94c6e58370fe608c163316a68.png 不知道为什么,欢迎各位同学指点。

2、CounterProvider

数据模型类

import 'package:flutter/material.dart';

class CounterProvider extends ChangeNotifier {
  int _count = 0;
  int get value => _count;

  void increment() {
    _count++;
    notifyListeners(); // 通知监听者数据变化
  } 
} 

继承ChangeNotifier, 初始化count,并提供一个get方法; 调用increment方法,会触发notifyListeners,这里会通知CounterProvider的订阅者更新UI。

3、MyProvider

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_drive/counter_provider.dart';
 
class MyProvider extends StatefulWidget {
  const MyProvider({super.key});
  @override
  State<MyProvider> createState() => _MyProviderState();
}

class _MyProviderState extends State<MyProvider> { 
  @override
  Widget build(BuildContext context) {
    CounterProvider counterProvider = Provider.of<CounterProvider>(context);

    return Scaffold(
      body: Center(
        child: Text("value = ${counterProvider.value}"),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.navigation),
        onPressed: (){
          counterProvider.increment();
        },
      ),
    );
  }
}

Provider.of() 可以获取共享实例对象,但是调用的widget会被重建。Provider.of() 有一个参数listen默认值为true,如果想在build()中访问状态,可以设置 listen: false 以减少不必要的重建。

Consumer

通过更细粒度的重构来帮助性能优化

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

class MyProvider extends StatefulWidget {
  const MyProvider({super.key});
  @override
  State<MyProvider> createState() => _MyProviderState();
}

class _MyProviderState extends State<MyProvider> {
  @override
  Widget build(BuildContext context) {
    // CounterProvider counterProvider = Provider.of<CounterProvider>(context);

    return Scaffold(
      body: Center(
        child: Consumer<CounterProvider>(
          builder: (context,  counterProvider, _) {
            return Text("value3 = ${counterProvider.value}");
          },
        ),
      ),
      floatingActionButton: Consumer(
        builder: (context, CounterProvider counterProvider, _) {
          return FloatingActionButton(
            child: const Icon(Icons.navigation),
            onPressed: () {
              counterProvider.increment();
            },
          );
        },
      ),
    );
  }
}

Consumer的child参数,可以将不需要更新重建的组件放在这里,减少重绘,提升性能。