前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >flutter如何进行状态管理

flutter如何进行状态管理

原创
作者头像
挥刀北上
修改2021-01-18 14:15:06
1.5K0
修改2021-01-18 14:15:06
举报
文章被收录于专栏:Node.js开发

在flutter中,如果我们的应用足够简单,数据流动的方向和顺序是清晰的,我们只需要将数据映射成视图就可以了。作为声明式的框架,Flutter 可以自动处理数据到渲染的全过程,通常并不需要状态管理。

但,随着产品需求迭代节奏加快,项目逐渐变得庞大时,我们往往就需要管理不同组件、不同页面之间共享的数据关系。当需要共享的数据关系达到几十上百个的时候,我们就很难保持清晰的数据流动方向和顺序了,导致应用内各种数据传递嵌套和回调满天飞。在这个时候,我们迫切需要一个解决方案,来帮助我们理清楚这些共享数据的关系,于是状态管理框架便应运而生。

下面来了解一下如何使用Provider进行状态管理,使用步骤如下:

1、首先安装Provider

代码语言:javascript
复制
dependencies:
  flutter:
    sdk: flutter
  provider: 3.0.0+1  #provider依赖

2、将需要共享的状态进行封装:

代码语言:javascript
复制
//定义需要共享的数据模型,通过混入ChangeNotifier管理听众
class CounterModel with ChangeNotifier {
  int _count = 0;
  //读方法
  int get counter => _count; 
  //写方法
  void increment() {
    _count++;
    notifyListeners();//通知听众刷新
  }
}

需要记忆点的知识点,需要定义一个类,类的属性和方法就是需要共享的状态,这个类需要混入ChangeNotifier。这个类能够帮助我们管理所有依赖资源封装类的听众。当资源封装类调用 notifyListeners 时,它会通知所有听众进行刷新。

3、将封装的状态放在组件最高层,因为 Provider 实际上是 InheritedWidget 的语法糖,所以通过 Provider 传递的数据从数据流动方向来看,是由父到子(或者反过来),所以一般就是把资源放到更高的层级。需要注意的是是如何放。

代码语言:javascript
复制

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
     //通过Provider组件封装数据资源
    return ChangeNotifierProvider.value(
        value: CounterModel(),//需要共享的数据资源
        child: MaterialApp(
          home: FirstPage(),
        )
    );
  }
}

可以看到,既然 Provider 是 InheritedWidget 的语法糖,因此它也是一个 Widget。所以,我们直接在 MaterialApp 的外层使用 Provider 进行包装,就可以把数据资源依赖注入到应用中,这里需要注意的是,由于封装的数据资源不仅需要为子 Widget 提供读的能力,还要提供写的能力,因此我们需要使用 Provider 的升级版 ChangeNotifierProvider。而如果只需要为子 Widget 提供读能力,直接使用 Provider 即可。

4、在子组件中通过of方法获取属性与方法,部署状态。

代码语言:javascript
复制

//第一个页面,负责读数据
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //取出资源
    final _counter = Provider.of<CounterModel>(context);
    return Scaffold(
      //展示资源中的数据
      body: Text('Counter: ${_counter.counter}'),
      //跳转到SecondPage
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondPage()))
      ));
  }
}

//第二个页面,负责读写数据
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //取出资源
    final _counter = Provider.of<CounterModel>(context);
    return Scaffold(
      //展示资源中的数据
      body: Text('Counter: ${_counter.counter}'),
      //用资源更新方法来设置按钮点击回调
      floatingActionButton:FloatingActionButton(
          onPressed: _counter.increment,
          child: Icon(Icons.add),
     ));
  }
}

以上便是使用Provider对flutter进行状态管理的过程,再看一个案例,如图:

图上是两个兄弟组件,我在在一个组件中展示数据,在另一个组件中点击按钮数据发生改变。代码如下:

代码语言:javascript
复制
import 'package:flutter/material.dart';

class Datashare extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [App1(), App2()],
    );
  }
}

class App1 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
      child: Text("111"),
    );
  }
}

class App2 extends StatelessWidget {
  // 获取属性与方法
  
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.redAccent,
      child: FlatButton(child: Text("加一"),color: Colors.redAccent,onPressed: ()=>{

      })
    );
  }
}

按照第一个案例的方法,我们对上面的代码进行改造:

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// 封装状态:
class CountContainer with ChangeNotifier {
  int _count = 0;
  int get counter => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

// class Datashare extends StatelessWidget {
//   @override
//   Widget build(BuildContext context) {
//     return Row(
//       children: [App1(), App2()],
//     );
//   }
// }

// 将封装的装填放到顶层组件;

class Datashare extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
        value: CountContainer(),
        child: Row(
          children: [App1(), App2()],
        ));
  }
}

class App1 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    final _counter = Provider.of<CountContainer>(context);
    print(_counter);
    return Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
      child: Text('${_counter._count}'),
    );
  }
}

class App2 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    final _counter = Provider.of<CountContainer>(context);
    return Container(
        width: 100,
        height: 100,
        color: Colors.redAccent,
        child: FlatButton(
            child: Text("加一"),
            color: Colors.redAccent,
            onPressed: () => {
                _counter.increment()
            }));
  }
}

需要注意的是这一句:_counter = Provider.of<CountContainer>(context),首先注意调用的地方,是在build函数中,因为在build函数中可以访问到context,然后是of函数的返回值的类型是封装的数据状态,此处不能省略。

上面的案例我们只定义了一个状态,如果是多个状态呢?

其实也不难。接下来,我就按照封装、注入和读写这 3 个步骤,与你介绍多个数据状态的共享。

此时我么需要MultiProvider,我们修改上面的代码,注入一个只读的数字,这个数字只做展示,局部代码如下:

代码语言:javascript
复制
class Datashare extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(providers: [
      Provider.value(value: 30.0),
      ChangeNotifierProvider.value(
          value: CountContainer(),
          )
    ],
    child: Row(
            children: [App1(), App2()],
          ));
  }
}

class App1 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    final _counter = Provider.of<CountContainer>(context);
    final textSize = Provider.of<double>(context);
    print(_counter);
    return Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
      child: Text('${_counter._count}----$textSize'),
    );
  }
}

我们只是修改了注入时的用法,增加了读取的用法,这里需要注意的是注入时Provider.value注入的是只读数据,不能被修改。

以上便是flutter中利用Provider进行状态管理的案例,希望对你有所帮助。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档