Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Riverpod - flutter 状态管理的应用

Riverpod - flutter 状态管理的应用

原创
作者头像
xcsoft
发布于 2024-07-31 00:52:02
发布于 2024-07-31 00:52:02
3901
举报
文章被收录于专栏:星辰日记星辰日记

## 前言

Riverpod 是 Flutter 下知名度较高的状态管理依赖,同样出自 Provider 的开发者 rrousselGit 之手。

其实仔细去看 Riverpod 似乎只是 Provider 的拼写打乱了顺序,其提供了更简洁的API 设计,实现了依赖注入。

如果去看过 rrousselGit 的主页,你可以发现,他也是著名的 Flutter_hooks 的作者,RiverPod 也理所当然的拥有 hook 相关的血统 > `HookConsumerWidget`, 我们可以在享受 hooks 的同时,直接使用`Widget.ref(provider).watch` 来监听变更并自动刷新页面。

## 为什么 Flutter 需要状态管理

Flutter 作为优秀的跨端框架,其使用的声明式UI有诸多优势,但嵌套的组件给数据传递带来了极大的挑战。

如果将数据在 组件类的构造函数中携带,并在数层中进行传递,随着代码量的提升,将会极大的增加代码的复杂和易理解程度。

因此状态管理组件出现了,其提供了一个清晰的模型来管理数据流,确保数据在正确的时机以正确的方式流动。这有助于避免数据不一致和难以追踪的 bug。通过集中的状态管理,我们可以更加容易的理解和增删需要传递的数据。

### 举个例子

我们可以使用最常见的 Flutter demo 来看, 在初始化完成项目之后,我们便可以看到这个例子

```dart

class MyHomePage extends StatefulWidget {

const MyHomePage({super.key, required this.title});

final String title;

@override

State<MyHomePage> createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

int _counter = 0;

void _incrementCounter() {

setState(() {

_counter++;

});

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

const Text(

'You have pushed the button this many times:',

),

Text(

'$_counter',

style: Theme.of(context).textTheme.headlineMedium,

),

],

),

),

floatingActionButton: FloatingActionButton(

onPressed: _incrementCounter,

tooltip: 'Increment',

child: const Icon(Icons.add),

),

);

}

}

```

因为 需要渲染的页面和按钮在 同一个组件 `MyHomePage` 下 因此我们可以很简单的在按钮点击的同时 setState 来使Flutter 感知数据的变化 并重新渲染页面。

#### 组件分离

但是 多数情况下, 我们需要渲染的页面,和改变数据的按钮 并不在一个组件中,例如,如果我们将这个按钮单独封装在一个类中。这种情况下,我们应该如何在点击按钮的时候增加数据呢?

```dart

class MyHomePage extends StatefulWidget {

const MyHomePage({super.key, required this.title});

final String title;

@override

State<MyHomePage> createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

const Text(

'You have pushed the button this many times:',

),

Text(

'${_counter._count}',

style: Theme.of(context).textTheme.headlineMedium,

),

],

),

),

floatingActionButton: const Button(),

);

}

}

class Button extends StatelessWidget {

const Button({super.key});

@override

Widget build(BuildContext context) {

return FloatingActionButton(

onPressed: _counter.increment,

tooltip: 'Increment',

child: const Icon(Icons.add),

);

}

}

```

#### 使用 ChangeNotify

ChangeNotify 是 Flutter 下用于监听数据变更的组件,在这个场景下,我们可以使用其监听 counter 的变化, 并重新渲染页面

```dart

class Counter extends ChangeNotifier {

int _count = 0;

int get count => _count;

void increment() {

_count++;

notifyListeners();

}

}

Counter _counter = Counter();

......

class _MyHomePageState extends State<MyHomePage> {

@override

void dispose() {

_counter.dispose();

super.dispose();

}

@override

void initState() {

super.initState();

_counter.addListener(() {

setState(() {});

});

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

const Text(

'You have pushed the button this many times:',

),

Text(

'${_counter._count}',

style: Theme.of(context).textTheme.headlineMedium,

),

],

),

),

floatingActionButton: const Button(),

);

}

}

......

```

#### 使用 RiverPod

再简单场景下,`ChangeNotify` 和 `ValueNotify` 已经能够胜任, 但对于复杂场景,还是有一定的局限性。

先添加如下依赖 (这里使用 Flutter_hooks 举例)

```yaml

dependencies:

flutter_hooks: ^0.20.5

hooks_riverpod: ^2.5.1

riverpod_annotation: ^2.3.5

dev_dependencies:

build_runner: ^2.4.11

riverpod_generator: ^2.4.0

```

别忘记在最外围增加一个 `ProvideScope`

```dart

void main() {

runApp(const ProviderScope(child: MyApp()));

}

```

接着新增一个 `counter_provider.dart` 文件

```dart

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'counter_provider.g.dart';

@Riverpod(keepAlive: true)

class Counter extends _$Counter {

@override

int build() => 0;

void increment() {

state++;

}

}

```

运行 代码生成

```shell

$ dart run build_runner build

```

他将会生成一个 `counter_provider.g.dart` 文件

```dart

// 接着我们可以使用 `ref.watch` 来监听数据的变化

ref.watch(counterProvider);

// 使用 ref.read().increment() 增加1

ref.read(counterProvider.notifier).increment;

```

完整的例子:

```dart

import 'package:daka/counter_provider.dart';

import 'package:flutter/material.dart';

import 'package:hooks_riverpod/hooks_riverpod.dart';

void main() {

runApp(const ProviderScope(child: MyApp()));

}

class MyApp extends StatelessWidget {

const MyApp({super.key});

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Flutter Demo',

theme: ThemeData(

colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),

useMaterial3: true,

),

home: const MyHomePage(),

);

}

}

class MyHomePage extends HookConsumerWidget {

const MyHomePage({super.key});

@override

Widget build(BuildContext context, WidgetRef ref) {

return Scaffold(

body: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

const Text(

'You have pushed the button this many times:',

),

Text(

ref.watch(counterProvider).toString(),

style: Theme.of(context).textTheme.headlineMedium,

),

],

),

),

floatingActionButton: const Button(),

);

}

}

class Button extends HookConsumerWidget {

const Button({super.key});

@override

Widget build(BuildContext context, WidgetRef ref) {

final counter = ref.read(counterProvider.notifier);

return FloatingActionButton(

onPressed: counter.increment,

tooltip: 'Increment',

child: const Icon(Icons.add),

);

}

}

```

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
看不懂呀
看不懂呀
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
【Flutter 工程】003-钩子函数:Flutter Hooks
Hooks 是 React 框架中引入的一项特性,用来分离状态逻辑和视图逻辑。如今,这个概念已经不仅限于 React,其他前端框架也在学习和借鉴。在 Flutter 开发中,业务逻辑和视图逻辑的耦合一直是一个比较突出的痛点,这也是各大前端框架常遇到的一个共性难题。为了解决这个问题,前端社区提出了许多方案,如MVP、MVVM、React 的Mixin、高阶组件(HOC),以及Hooks。在Flutter中,开发者可能对Mixin比较熟悉。但是,Mixin的应用也存在一定的局限性:
訾博ZiBo
2025/01/06
2610
【Flutter 工程】003-钩子函数:Flutter Hooks
小荷才露尖尖角,和Flutter应用说你好
当按钮点击,就调用这个函数,改变状态会使用setState方法,这个和React的类组件汇总改变状态的方式很像
用户6256742
2024/06/13
1340
【Flutter 工程】005-代码分离实践:flutter_hooks & functional_widget
在Flutter开发中,“嵌套地狱”(Nesting Hell)是指在构建复杂的UI布局时,由于多层嵌套的组件结构,代码变得冗长、难以维护和理解的情况。
訾博ZiBo
2025/01/06
1250
【Flutter 工程】005-代码分离实践:flutter_hooks & functional_widget
Flutter中的状态管理
Flutter作为出自Google的一个跨平台(iOS,Android)应用开发方案。布局方式上和React或者说React Native非常相似——组件(Widget)化。写起来非常的高效,却有着React Native所不具有的优势: 一套代码到处运行,原生渲染,原生调用,不需要像RN需要桥接。
小刀c
2022/08/16
1.4K0
Flutter中的状态管理
flutter鸿蒙版本mvvm架构思想原理
在Flutter中实现MVVM(Model-View-ViewModel)架构是为了将UI(视图)与业务逻辑(模型和视图模型)分离,提高代码的可维护性和可读性。
淼学派对
2024/11/04
2110
[- Flutter 数据&状态篇 -] InheritedWidget
一个界面是由众多组件拼组而成。经常需要将一个组件进行封装,但此时有一个问题,如何让多个组件去共享一些值。 比如下面在一个_State中使用了WidgetA组件,传入_incrementCount
张风捷特烈
2020/04/30
3860
[- Flutter 数据&状态篇 -]  InheritedWidget
推荐一种简单的在Flutter中分离View与Model的方法
我们在做Flutter开发的时候主要会在State中加入很多自己的业务逻辑,例如网络请求,数据处理等等,如果你的业务逻辑比较复杂的话会面对着一个越来越膨胀的State。代码的可读性下降,日后维护也越来越困难。这和我们在开发Android的时候遇到巨无霸Activity是同样的问题。解决办法就是分层解耦。Android从MVC进化到MVP/MVVM。Flutter 也有开发者把MVP引入到Flutter来解决这个问题。这里我们来看另一种比较简单的方法。
HowHardCanItBe
2020/09/15
1.6K0
[ - Flutter 状态篇 redux - ] StoreConnector还是StoreBuilder,让distinct把好关
很多天没发文了,今天翻翻源码,发现解决一个困扰我的问题:redux中的StoreConnector还是StoreBuilder似乎都可以定点刷新,控制粒度。那它们有什么区别呢?在官方样例中基本都用St
张风捷特烈
2020/04/30
1.1K0
[ - Flutter 状态篇 redux - ] StoreConnector还是StoreBuilder,让distinct把好关
动手编写你的第一个 Flutter 应用
我将带领大家尝试编写一个 Flutter 应用,感受一下 Flutter 开发的语法特点和运行效率。
CSDN技术头条
2020/02/26
1.1K0
flutter鸿蒙版本mvvm架构思想原理
在Flutter中实现MVVM(Model-View-ViewModel)架构是为了将UI(视图)与业务逻辑(模型和视图模型)分离,提高代码的可维护性和可读性。
淼学派对
2024/10/08
2530
flutter基础布局代码
骨灰级别的基础代码,只是做个简单的记录,方便以后看 都是用dart写的,都在flutter项目下的lib文件夹下 import 'package:flutter/material.dart'; import './tomFont.dart'; void main() { runApp( MaterialApp( theme: ThemeData( primarySwatch: Colors.yellow, ), home: Scaffold(
Tom2Code
2023/02/14
7600
flutter基础布局代码
Flutter的两种本地存储方式之 SharedPreferences(1)
缓存少量的键值对信息(比如记录用户是否阅读了公告,或是简单的计数),可以使用 SharedPreferences。
徐建国
2021/08/06
1.4K0
Flutter Lesson 3:Flutter组件(widget)前篇
介绍完Flutter开发环境的搭建以及Dart基础语法,我们就可以着手进行开发了。一般我们开始学习一门技术或者是一门语言的时候,都会写一个Hello World的Demo。所以,撸起袖子开始干。不过在职之前,我们先来看看Flutter项目的默认文件以及目录结构。
踏浪
2019/07/31
9560
Flutter Lesson 3:Flutter组件(widget)前篇
重走Flutter状态管理之路—Riverpod入门篇
熟悉我的朋友应该都知道,我好几年前写过一个「Flutter状态管理之路」系列,那个时候介绍的是Provider,这也是官方推荐的状态管理工具,但当时没有写完,因为写着写着,觉得有很多地方不尽人意,用着很别扭,所以在写了7篇文章之后,就暂时搁置了。
用户1907613
2022/05/17
3.6K0
「 flutter 必知必会 」详细解析数据共享 InheritedWidget 完整使用
「 flutter 必知必会 」贴心解析:状态管理与数据共享 InheritedWidget 完整使用方案,为你铺平大前端学习之路
圆号本昊
2021/09/24
8370
「 flutter 必知必会 」详细解析数据共享 InheritedWidget 完整使用
在 Flutter 移动应用程序中创建一个列表
Flutter 是一个流行的开源工具包,它可用于构建跨平台的应用。在文章《用 Flutter 创建移动应用》中,我已经向大家展示了如何在 Linux 中安装 Flutter 并创建你的第一个应用。而这篇文章,我将向你展示如何在你的应用中添加一个列表,点击每一个列表项可以打开一个新的界面。这是移动应用的一种常见设计方法,你可能以前见过的,下面有一个截图,能帮助你对它有一个更直观的了解:
用户1880875
2021/09/06
3.8K0
01-HelloFlutter
https://gitee.com/andli/hello-flutter.git
专注APP开发
2019/11/07
4090
Flutter | 常用组件分类、概述、实战
AppBar(title属性,Text组件; action:动作响应;!!!! titleSpacing:标题文字间距; toolbarOpacity:标题透明度;)
凌川江雪
2020/06/16
4.5K0
Flutter 第一个程序Hello World!
  Flutter实际上在我学习Android之前就已经听说过了,不过那时候的Flutter还是初始版本,并不如原生,虽说有跨平台的优势,但也只是了解而已,没有去正式使用,那么为什么又要学习了呢?
晨曦_LLW
2022/09/09
1.4K0
Flutter 第一个程序Hello World!
Flutter 构建完整应用手册-持久化
如果我们有一小部分我们想要保存的键值,我们可以使用shared_preferences插件。
南郭先生
2018/08/14
1.7K0
相关推荐
【Flutter 工程】003-钩子函数:Flutter Hooks
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档