【Flutter】状态管理provider(二)Selector

346 阅读1分钟

前言

Selector是比Consumer更细颗粒度的管理方式,Consumer可以监听Provider所有数据变化,而Selector可以监听一个或者多个数据的变化。

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) {

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

当点击FloatingActionButton时,会打印

I/flutter ( 5378): FloatingActionButton调用

I/flutter ( 5378): Text展示调用

说明两个位置都会被builder,而floatingActionButton位置只是调用方法,并没有展示,没有必要重新build,所以可以使用使用Selector来代替Consumer

Selector

class Selector<A, S> extends Selector0<S> {
  /// {@macro provider.selector}
  Selector({
    Key? key,
    required ValueWidgetBuilder<S> builder,
    required S Function(BuildContext, A) selector,
    ShouldRebuild<S>? shouldRebuild,
    Widget? child,
  }) : super(
          key: key,
          shouldRebuild: shouldRebuild,
          builder: builder,
          selector: (context) => selector(context, Provider.of(context)),
          child: child,
        );
}

Selector提供了builder,selector,shouldRebuild和child四个属性,selector和builder属于必选项。

1、selector属性

方法中包含两个参数,方法返回转换后的数据类型,函数原型为S Function(BuildContext, A) selector

  • BuildContext:主要用来创建Widget,为创建Widget提供上下文环境;
  • A:它是泛型类型,它用来表示共享数据对象,通过该对象的getter方法可以获取到共享数据,然后就可以转换数据类型;
  • S:它是泛型类型,它用来表示转换数据类型后的对象,它和builder属性中的第二个参数类型相同;

2、builder属性

方法中包含三个参数,方法返回Widget对象。 该方法中三个参数如下:

  • context:主要用来创建Widget,为创建Widget提供上下文环境;
  • value:是泛型类型,它用来表示转换数据类型后的对象;
  • child:表示Selector组件的子组件,因此它代表的对象和Selector组件的child属性代表的对象相同;

3、shouldRebuild属性

方法中包含两个参数,方法返回true或者false.返回值表示是否更新组件以及组件中的共享数据。该属性是可选属性,默认返回false。

  • previous:它是泛型类型,它用来表示转换前数据类型的对象;
  • next:它是泛型类型,它用来表示转换后数据类型后的对象;
    注意:这两个属性的类型相同,表示把共享数据类型转换后的数据类型,也就是selecttor属性中的S。

使用

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, _) {
            print("Text展示调用");
            return Text("value3 = ${counterProvider.value}");
          },
        ),
      ),
      floatingActionButton: Selector<CounterProvider,CounterProvider>(
        selector: (context,provider) => provider,
        shouldRebuild: (previous, next) => false,
        builder: (context,   counterProvider, _) {
          print("FloatingActionButton调用");
          return FloatingActionButton(
            child: const Icon(Icons.navigation),
            onPressed: () {
              counterProvider.increment();
            },
          );
        },
      ),
    );
  }
}

再次点击FloatingActionButton时,只会打印“Text展示调用”

总结

使用Selector可以减少不必要的 widget 重建,提升应用的响应速度和流畅度。