flutter中状态管理介绍

问题背景

响应式的编程框架中都会有一个永恒的主题——“状态(State)管理”,无论是在 React/Vue(两者都是支持响应式编程的 Web 开发框架)还是 Flutter 中,他们讨论的问题和解决的思想都是一致的。我们想一个问题,StatefulWidget的状态应该被谁管理?答案是取决于实际情况!以下是管理状态的最常见的方法: Widget 管理自己的状态。 Widget 管理子 Widget 状态。 混合管理(父 Widget 和子 Widget 都管理状态)。 如何决定使用哪种管理方法? 如果状态是用户数据,如复选框的选中状态、滑块的位置,则该状态最好由父 Widget 管理。 如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由 Widget 本身来管理。 如果某一个状态是不同 Widget 共享的则最好由它们共同的父 Widget 管理。 在 Widget 内部管理状态封装性会好一些,而在父 Widget 中管理会比较灵活。有些时候,如果不确定到底该怎么管理状态,那么推荐的首选是在父 Widget 中管理(灵活会显得更重要一些)。

问题分析

(1)Widget管理自身状态 我们实现一个TapboxA,在它对应的_TapboxAState 类: 管理TapboxA的状态。 定义_active变量:确定盒子的当前颜色的布尔值。 定义_handleTap()函数,该函数在点击该盒子时更新_active的值,并调用setState()方法以更新UI。 (2)父Widget管理子Widget的状态 对于父Widget来说,管理状态并告诉其子Widget何时更新通常是比较好的方式。 在后面的示例中,TapboxB通过回调将其状态导出到其父组件,状态由父组件管理,因此它的父组件为StatefulWidget。但是由于TapboxB不管理任何状态,所以TapboxB为StatelessWidget。 ParentWidgetState 父类组件需要实现的功能: 为TapboxB 管理_active状态。 实现_handleTapboxChanged(),当盒子被点击时调用的方法。 当状态改变时,调用setState()更新UI。 TapboxB 子组件类的功能: 继承StatelessWidget类,因为所有状态都由其父组件处理。 当检测到点击时,它会通知父组件。

问题解决

上面对两种实现(1)Widget管理自身状态(2)父Widget管理子Widget的状态的实现方式进行了基本分析。下面直接上代码: (1)Widget管理自身状态,代码如下:

import 'package:flutter/material.dart';


class Test extends StatefulWidget {
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  bool _active = false;

  void _handleTap() {
    setState(() {
      _active = !_active;
    });
  }

  Widget build(BuildContext context) {
    return GestureDetector(
      // 点击回调_handleTap方法设置state并重新渲染
      onTap: _handleTap,
      child: Container(
        child: Center(
          child: Text(
            _active ? 'Active' : 'Inactive',
            style: TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: _active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
      ),
    );
  }
}

运行结果如下: 1680850682494.gif

(2)父Widget管理子Widget的状态,代码如下:

import 'package:flutter/material.dart';


class Test extends StatefulWidget {
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  bool _active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: TapBoxB(
        active: _active,
        // 回调_handleTapboxChanged方法
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

//------------------------- TapBoxB ----------------------------------

class TapBoxB extends StatelessWidget {
  TapBoxB({Key? key, this.active = false, required this.onChanged})
      : super(key: key);

  final bool active;
  final ValueChanged<bool> onChanged;

  void _handleTap() {
    // 回调onChanged方法,onChanged作为成员变量函数由构造方法传入
    onChanged(!active);
  }

  Widget build(BuildContext context) {
    return GestureDetector(
      // 响应点击事件
      onTap: _handleTap,
      child: Container(
        child: Center(
          child: Text(
            active ? 'Active' : 'Inactive',
            style: TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
      ),
    );
  }
}

运行结果如下: 1680850682494.gif

问题总结

本文介绍了flutter中状态管理的基本实现方式,(1)Widget管理自身状态(2)父Widget管理子Widget的状态,有兴趣的同学可以进一步深入研究。