Flutter基础--状态管理

更新日期: 2019-09-20阅读: 2.8k标签: 状态

当我们使用编译器创建一个新Flutter应用的时候,我们可以在主界面看到两个小部件StatelessWidget和StatefulWidget。这是两个最常见使用最频繁的小部件了。


StatelessWidget ,StatefulWidget

  1. StatelessWidget 状态不可改变的,它内部的数值和UI都应该是常量不可改变
  2. StatefulWidget 状态可变,我们可以通过点击,或者网络获取数据等来动态的改变界面。

假如我们要实现如下图的功能,点击加一。如果使用StatelessWidget,会发现点击的时候count是加一了,但是界面没有刷新。应该使用StatefulWidget,当count加一的时候通过 setState(() { _count++;}); 方法来改变count的值,这时候就发现界面可以刷新了。

比如

import 'package:flutter/material.dart';

class StateManagerDemo extends StatefulWidget {
  @override
  _StateManagerDemoState createState() => _StateManagerDemoState();
}

class _StateManagerDemoState extends State<StateManagerDemo> {
  int _count = 0;
  void countCallBack(){
    setState(() {
      _count++;
    });
    debugPrint('$_count');
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('StateManagerDemo'),
        elevation: 0.0,
      ),
      body: Counter0(_count),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: countCallBack,
      ),
    );
  }
}
//------
class Counter0 extends StatelessWidget {
  final int count;
  Counter0(this.count);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Chip(
        label: Text('$count'),
      ),
    );
  }
}
//-----
class Counter extends StatelessWidget {
  final int count;
  final VoidCallback voidCallback;
  Counter(this.count,this.voidCallback);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ActionChip(
        label: Text('$count'),
        onPressed: voidCallback,
      ),
    );
  }
}

上面的代码中,StateManagerDemo有两个子部件Counter0和Counter。当我们点击按钮的时候,_count的值++,然后传递给子部件。

Counter0是直接接受父部件传过来的参数。

Counter不仅接收父部件传过来的参数,还有一个回调。这样点击它的时候,会执行父部件中的回调方法,也能改变自身的显示。


InheritedWidget

上面的情况是只有一层,比如Counter小部件中使用了父部件的count这个变量,假如Counter没有用到这个变量而是它的子类用到了这个变量,我们还要一层一层的传下去吗,这有点麻烦啊,这时候可以使用InheritedWidget这个类来管理。

import 'package:flutter/material.dart';

//使用InheritedWidget来管理状态,
class ContentProvider extends InheritedWidget {
  final int count;
  final VoidCallback countCallBack;
  final Widget child;
  const ContentProvider({
    this. count,
     this. countCallBack,
    this. child,
  }): assert(child != null),
        super(child: child);

  static ContentProvider of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(
        ContentProvider) as ContentProvider;
  }
  //是否通知继承该小部件的小部件更新
  @override
  bool updateShouldNotify(ContentProvider old) {
    return true;
  }
}
class StateManagerDemo extends StatefulWidget {
  @override
  _StateManagerDemoState createState() => _StateManagerDemoState();
}

class _StateManagerDemoState extends State<StateManagerDemo> {
  int _count = 0;
  void countCallBack(){
    setState(() {
      _count++;
    });
    debugPrint('$_count');
  }
  @override
  Widget build(BuildContext context) {
  //ContentProvider放在最外层,指定参数count和callback
    return ContentProvider(
      count: _count,
      countCallBack: countCallBack,
      child: Scaffold(
        appBar: AppBar(
          title: Text('StateManagerDemo'),
          elevation: 0.0,
        ),
        body: Counter1(),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: countCallBack,
        ),
      ),
    );
  }
}

class Counter1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //直接使用ContentProvider中的参数
    final int count = ContentProvider.of(context).count;
    final VoidCallback voidCallback = ContentProvider.of(context).countCallBack;
    return Center(
      child: ActionChip(
        label: Text('$count'),
        onPressed: voidCallback,
      ),
    );
  }
}

首先定义一个数据提供者ContentProvider继承InheritedWidget,里面定义我们需要的count和回调。提供一个of方法让外界可以拿到它的实例,方便拿到方法。

然后将这个ContentProvider放在主布局的最外层,并传入需要的参数count和callBack。这样它的子部件中就都能访问到这个参数了。

最后在子部件Counter1中直接使用ContentProvider中的参数。


ScopedModel

还可以使用ScopedModel来完成状态管理

这是一个第三方的库,该库最初是从Fuchsia代码库中提取的,使用时需要先导入包,在pubspec.yaml文件中添加依赖

dependencies:
   scoped_model: 1.0.1

https://pub.dev/packages?q=scoped_model 这里可以看到最新版本。使用这个库的时候我们在StatelessWidget中也可以改变UI

该库主要分为三个部分

  1. Model class 扩展此类以创建自己的模型,例如SearchModel或UserModel。我们可以监听数据的变化!
  2. ScopedModel 小部件 把Model包装到ScopedModel中,它内部的所有部件都能拿到model中的数据
  3. ScopedModelDescendant 只要Model发生改变 它就会改变

比如用ScopedModel实现前面的功能

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

class CountModel extends Model{
   int _count = 0;
   int get count =>_count;

   void countIncrease(){
     _count ++;
     //通知改变
     notifyListeners();
   }
}

class StateModelDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModel<CountModel>(
      model: CountModel() ,
      child: Scaffold(
        appBar: AppBar(
          title: Text('StateModelDemo'),
        ),
        body: Counter2(),
        floatingActionButton: ScopedModelDescendant<CountModel>(
          rebuildOnChange: false,
          builder: (context, child, model) => FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: (){
              model.countIncrease();
            },
          ),
        ),
      ),
    );
  }
}

class Counter2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModelDescendant<CountModel>(
      builder: (context, child, model) => Center(
        child: ActionChip(
          label: Text('${model.count}'),
          onPressed: (){
            model.countIncrease();
          },
        ),
      ),
    );
  }
}


Mobx

Mobx在前端中用的多,且很好用,所以Flutter也引入了,对于我们Android开发者来说跟学前面的成本都一样哈哈。

查看版本:https://pub.dev/packages?q=Mobx
github:https://github.com/mobxjs/mobx.dart/tree/master/mobx_codegen

首先需要去pubspec.yaml文件中引入依赖

dependencies:
  mobx: ^0.3.8
  flutter_mobx: ^0.3.3
dev_dependencies:
  mobx_codegen: ^0.3.9
  build_runner: ^1.7.0

然后开始使用mobx完成之前的功能

首先创建一个store类

import 'package:mobx/mobx.dart';
//包含生成的文件
part 'state_manager_demo.g.dart';

class Counter = _Counter3 with _$Counter;

abstract class _Counter3 with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

创建完成之后,我们会发现part后面的内容和_$Counter都会报错。说是找不到,需要我们生成。来到AndroidStudio的terminal窗口执行下面命令来生成文件

flutter packages pub run build_runner build

这时候就可以看到我们自己的文件state_manager_demo.dart文件旁边生成了一个新文件state_manager_demo.g.dart,而且不在报错了。

如果想要修改后.g.dart文件也能自动修改执行

pub run build_runner watch

下面去界面中使用它

class MobxDemo extends StatefulWidget {
  @override
  _MobxDemoState createState() => _MobxDemoState();
}

class _MobxDemoState extends State<MobxDemo> {
  final Counter counter = Counter();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('StateModelDemo'),
      ),

      body: Center(
        child: Observer(
            builder: (_)=>ActionChip(
              label: Text('${counter.value}'),
              onPressed: (){
                counter.increment();
              },
            ),
        ),
      ),

      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed:(){
          counter.increment();
        },
      ),
    );
  }
}

很简单继承StatefulWidget,需要监听的小部件使用Observer包裹起来。然后创建一个成员变量 final Counter counter = Counter(); 内部就可以直接使用Counter中的变量和方法了。运行效果跟前面的一样。

综合来看这几种状态管理的方式 ,我感觉Mobx是最好用的一个。

原文 https://chsmy.github.io/2019/09/22/flutter/Flutter基础-状态管理/

链接: https://www.fly63.com/article/detial/5456

Javascript 状态管理工具 DataSet ,实现数据的订阅、查询、撤销和恢复

网页是用户与网站对接的入口,当我们允许用户在网页上进行一些频繁的操作时,对用户而言,误删、误操作是一件令人抓狂的事情,“如果时光可以倒流,这一切可以重来……”。

理解 React 轻量状态管理库 Unstated

在React写应用的时候,难免遇到跨组件通信的问题。现在已经有很多的解决方案。React本身的Context,Redux结合React-redux,Mobx结合mobx-react

你再也不用使用 Redux、Mobx、Flux 等状态管理了

这个库的作者希望使用 React 内置 API ,直接实现状态管理的功能。看完这个库的说明后,没有想到代码可以这个玩。短短几行代码,仅仅使用 React Hooks ,就实现了状态管理的功能。

为什么要使用状态管理

我们平时开发的大部分项目,由于复杂度不够, 很少使用 Vuex、Redux 等状态管理库,就算引入了 Vuex 这些库,也只是当作一个全局数据引用,并非对应用状态进行管理。但一旦页面的复杂度比较高,必然要引入状态管理,今天就聊聊我理解中的状态管理。

React使用Hooks与Context替代Redux状态管理

React Hooks 在 2018 年年底就已经公布了,正式发布是在 2019 年 5 月,关于它到底能做什么用,并不在本文的探讨范围之内,本文旨在摸索,如何基于 Hooks 以及 Context,实现多组件的状态共享,完成一个精简版的 Redux。

如何使用react hooks来进行状态管理?

首先要明确为什么要使用redux,这一点很重要,如果不知道为什么使用redux,那么在开发的过程中肯定不能合理的使用redux.首先来看redux的本质:redux做为一款状态管理工具,主要是为了解决组件间通信的问题。

共享可变状态中出现的问题以及如何避免?

本文回答了以下问题:么是共享可变状态?为什么会出现问题?如何避免其问题?标有(高级)的部分会更深入,如果你想更快地阅读本文,可以跳过。

使用Observable实现Vue全局状态共享

项目不大, 又不想用Vuex, 那么使用Observable来实现状态共享也不失为一个选择。用法 :让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象

node如何实现保持登录状态?

当我们登录成功,在这个页面刷新,页面并没有保存登录状态;今天我们就来看一下如何在后台使用cookie保存用户登录状态。做到刷新页面仍然显示在用户登录界面。node实现保持登录状态的方法如下:

3条简单的React状态管规则

React组件内部的状态是在渲染之间保持不变的封装数据。useState()是React钩子,负责管理功能组件内部的状态。我喜欢useState()确实使状态处理变得非常容易。但是我经常遇到类似的问题:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!