riverpod中的StateProvider 和 NotifierProvide

824 阅读4分钟

一、介绍 NotifierProvider

NotifierProvider 是 Riverpod 库中的一个概念,用于在 Flutter 应用中管理状态。Riverpod 是一个状态管理库,提供了一种声明式和安全的方式来访问和修改应用的状态。NotifierProvider 是其中一种 Provider 类型,专门用于和 ChangeNotifier (或类似的可以发出通知的对象) 一起使用,以便在状态发生变化时,能够通知监听者更新 UI。

基本概念

  • ChangeNotifier: 它是 Flutter 的一个类,专门用于管理可监听的状态。当使用 ChangeNotifier 管理状态时,你可以通过调用 notifyListeners() 方法来通知所有监听者状态已经改变,这样监听者就可以做出相应的反应(比如更新 UI)。
  • NotifierProvider: 在 Riverpod 中,NotifierProvider 用于创建和提供一个 ChangeNotifier。它负责监听状态变化,并在变化时重新构建监听这个状态的 widgets。

使用 NotifierProvider

要使用 NotifierProvider,你首先需要定义一个继承自 ChangeNotifier 的类,用于管理你想要共享的状态。

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // 通知监听者状态已改变
  }
}

然后,你可以通过 NotifierProvider 将这个 Counter 类的实例提供给应用中的其他部分。

final counterProvider = NotifierProvider((ref) => Counter());

访问状态

在需要访问这个状态的 widget 中,你可以使用 Consumer widget 或者 ref.watch 方法来读取状态:

class CounterWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 使用 ref.watch 来监听 counterProvider 的状态
    final counter = ref.watch(counterProvider);

    return Text('${counter.count}');
  }
}

更新状态

当你需要更新状态时,可以通过 ref.read 获取 Counter 实例,并调用它定义的方法:

ElevatedButton(
  onPressed: () {
    // 获取 Counter 实例并调用 increment 方法来更新状态
    ref.read(counterProvider.notifier).increment();
  },
  child: Text('Increment'),
)

总结

NotifierProvider 提供了一种在 Flutter 应用中管理和共享状态的高效方式。通过与 ChangeNotifier 结合使用,它能够在状态变化时通知监听者,使得状态管理更加简单和直观。Riverpod 的这种方式不仅提高了代码的可维护性,还增加了类型安全性和测试的便利性。

二、StateProvider 又是什么呢?

StateProvider 是 Riverpod 库中另一种常用的 Provider 类型,用于管理和提供简单的同步状态。与 NotifierProvider 不同,StateProvider 专为简单状态设计,适用于那些不需要复杂逻辑或多个方法来修改状态的场景,如计数器、开/关状态、文本输入等。

基本用法

使用 StateProvider,你可以很容易地创建和管理一个同步的状态。这种状态是响应式的,当状态改变时,所有使用这个状态的 widgets 都会被重新构建。

定义一个 StateProvider

final counterProvider = StateProvider((ref) => 0);

这里,counterProvider 是一个初始值为 0 的计数器状态。ref 参数可以用来访问其他 providers,但在这个简单的例子中我们不需要它。

读取状态

在 widget 中,你可以使用 ConsumerWidget 或 ref.watch 来读取 StateProvider 的状态:

class CounterDisplay extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 直接监听 counterProvider 的当前状态值
    final count = ref.watch(counterProvider);

    return Text('$count');
  }
}

更新状态

要更新 StateProvider 管理的状态,你可以使用 ref.read 方法获取状态,并调用它的 .state 属性进行更新:

ElevatedButton(
  onPressed: () {
    // 更新 counterProvider 的状态
    ref.read(counterProvider.state).state++;
  },
  child: Text('Increment'),
)

特点和优势

  • 简单性:对于简单的状态管理需求,StateProvider 提供了一种非常直接和简洁的方式。
  • 响应式StateProvider 使状态管理成为响应式的,当状态改变时,所有依赖该状态的 widgets 自动更新。
  • 可测试性:与 Riverpod 中的其他 provider 一样,StateProvider 也支持依赖注入和覆写,使得测试变得更加容易。

总之,StateProvider 是 Riverpod 提供的一种用于管理简单同步状态的工具,它既简单易用,又能满足大多数基本的状态管理需求。对于更复杂的状态管理场景,你可能需要考虑使用 StateNotifierProviderChangeNotifierProvider 或其他更高级的 Provider 类型。

三、使用StateNotifierProvider

StateNotifier是一个轻量级的状态管理类,它允许你定义一个内部状态,并提供更新这个状态的方法。每当状态发生变化时,所有监听这个状态的监听者都会被通知。

import 'package:state_notifier/state_notifier.dart';

class CounterStateNotifier extends StateNotifier<int> {
  CounterStateNotifier() : super(0);

  void increment() {
    state = state + 1; // 更新状态
  }
}

在上面的例子中,我们定义了一个CounterStateNotifier类,它继承自StateNotifier<int>。初始状态被设置为0。我们还定义了一个increment方法来增加计数器的值。

使用StateNotifierProvider对StateNotifier进行包装:

要在Riverpod中使用StateNotifier进行状态管理,你可以使用StateNotifierProvider。这让你能够在你的应用中访问和监听状态的变化。

final counterProvider = StateNotifierProvider<CounterStateNotifier, int>((ref) {
  return CounterStateNotifier();
});

在这个例子中,counterProvider是一个StateNotifierProvider,它创建并提供了CounterStateNotifier的实例。这个Provider的状态类型是int,因为CounterStateNotifier管理的是一个整数状态。

在UI中使用StateNotifierProvider

在Flutter应用中,你可以通过ConsumerWidgetConsumer来监听和使用由StateNotifierProvider提供的状态:

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: Text('Count: $count', style: TextStyle(fontSize: 20)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider.notifier).increment(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个例子中,我们在CounterScreen中使用ConsumerWidget来监听counterProvider的状态(即计数器的值)。我们还通过floatingActionButton提供了一个增加计数器值的按钮。当按钮被点击时,我们通过调用ref.read(counterProvider.notifier).increment()来增加计数器的值。

总结

StateNotifierProvider提供了一个强大而灵活的方式来管理Flutter应用中的状态。通过将StateNotifier的概念与Riverpod的能力结合,它提供了一种清晰、可测试和可预测的方式来管理和更新应用的状态。此外,由于StateNotifier与UI是分离的,这种方式促进了更好的代码组织和可维护性。

StateNotifierProviderStateNotifier之间的关系

StateNotifierProviderStateNotifier之间的关系体现在StateNotifierProvider负责创建和提供StateNotifier实例,而StateNotifier负责管理状态和通知状态变化。这种设计允许开发者将状态管理逻辑(在StateNotifier中)与界面逻辑(在使用StateNotifierProvider的Flutter部件中)分离,从而使得应用更加模块化和易于维护。此外,StateNotifierProviderStateNotifier的组合也使得状态的测试和模拟变得更加容易。

四、ChangeNotifierProvider

ChangeNotifierProvider是Riverpod包中提供的另一种状态管理工具,它是基于Flutter框架内的ChangeNotifier类构建的。ChangeNotifier是一个简单的混入(mixin),提供了一个可以被任何对象监听的变更通知机制。当使用ChangeNotifier来管理状态时,你可以通过调用notifyListeners方法来通知监听者状态已经改变。ChangeNotifierProviderChangeNotifier结合使用,使得在Riverpod状态管理库中处理状态变更变得简单而高效。

ChangeNotifier

首先,了解下ChangeNotifier的基本用法。你可以通过继承ChangeNotifier来创建一个可以通知其监听者状态变化的类:

import 'package:flutter/foundation.dart';

class CounterNotifier extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // 通知监听者状态已改变
  }
}

在上面的例子中,CounterNotifier类包含了一个私有的计数器状态_count和一个increment方法。每次调用increment方法时,计数器的值都会增加,并通过调用notifyListeners方法来通知所有监听者该状态已更新。

使用ChangeNotifierProvider

要在Riverpod中使用ChangeNotifier进行状态管理,你可以使用ChangeNotifierProvider。这允许应用的其他部分访问和监听ChangeNotifier的实例。

final counterProvider = ChangeNotifierProvider((ref) {
  return CounterNotifier();
});

这里,counterProvider是一个通过ChangeNotifierProvider创建的CounterNotifier的实例。这意味着你可以在应用的其他地方监听和响应计数器状态的变化。

在UI中使用ChangeNotifierProvider

在Flutter应用的UI部分,你可以通过ConsumerConsumerWidget来监听和响应状态变化:

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

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counterNotifier = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: Text('Count: ${counterNotifier.count}', style: TextStyle(fontSize: 20)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider).increment(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

CounterScreen中,我们使用ref.watch来监听counterProvider的变化,并通过FloatingActionButton提供了一个途径去调用increment方法来更新计数器的值。每当计数器的值变化时,通过ChangeNotifiernotifyListeners方法,所有监听该状态的部件都会自动重建以反映最新的状态。

总结

ChangeNotifierProvider提供了一种简单而强大的方式来在Flutter应用中进行状态管理。通过结合使用ChangeNotifierChangeNotifierProvider,你可以创建可监听的状态对象,并在状态变化时自动通知应用的其他部分。这种方式特别适合于需要跨多个部件共享状态的场景。此外,由于ChangeNotifier的实现是基于监听器模式的,这提供了一种高效且易于理解的方式来响应状态变化。