likes
comments
collection
share

Flutter状态管理-基础概念

作者站长头像
站长
· 阅读数 49

基础概念

目录

Flutter 应用是 声明式 的,这也就意味着 Flutter 构建的用户界面就是应用的当前状态。

Flutter状态管理-基础概念

Flutter框架是声明式UI,即状态驱动页面变化。所谓状态就是构建用户界面的数据,比如文本显示的文案、图片显示的url、按钮是否显示的变量等等,所以声明式UI的核心就是数据驱动UI。开发的关注点在状态(数据)上,当我们改变状态时,用户界面会自动重新构建。

声明式UI和命令式UI

声明式UI(Declarative UI)和命令式UI(Imperative UI) 有很大的不同,比如React、Vue、SwiftUI、Compose、Flutter是声明式UI框架,UIKit、Android Views、jQuery则是命令式UI框架。

从UI编写和视图更新两方面来理解两者的区别:

  • 在UI编写方面,声明式UI更注重视图的描述和最终呈现,代码简洁,属于更高一级的抽象;命令式UI则需要控制具体的细节,通过明确每一步的实现来构建UI。
  • 在视图更新方面,声明式UI关注点在状态上,通过改变状态来更新视图,由框架负责处理UI的渲染和更新;而命令式UI需要直接操作原始UI来更新数据。开发者需要手动控制UI的各个方面。

UIKit VS SwiftUI

从UIKit和SwiftUI举例对比来更好的理解命令式UI和声明式UI的视图编写区别:

  • SwiftUI(声明式UI):
    Text("Hello, World!")
      .font(.title)
      .foregroundColor(.blue);
    
  • UIKit(命令式UI):
    // UIKit 声明UILable
    UILabel label = UILabel(frame: CGRect(x: 50, y: 100, width: 200, height: 50));
    label.text = "Hello, World!";
    label.font = UIFont.boldSystemFont(ofSize: 20);
    label.textColor = UIColor.blue;
    

从示例对比可以看出,声明式UI的描述形式更简洁,更注重视图的描述;而命令式UI需要控制UI的具体细节

Vue VS jQuery

Vue.js是声明式UI框架,通过数据驱动视图变化,无需操作真正的DOM,而jQuery是命令式UI框架,需要通过操作DOM的方式来修改DOM。

  • Vue,通过更新数据message这个状态来更新视图
    // Vue
    <template>
      <div>
        <p>{{ message }}</p>
        <button @click="updateMessage">Update Message</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          message: 'Hello, Vue!'
        };
      },
      methods: {
        updateMessage() {
          this.message = 'Hello, World!';
        }
      }
    };
    </script>
    
  • jQuery,通过$('#message').text('Hello, World!')操作真实的DOM更新UI视图
    // jQuery
    <div id="app">
      <p id="message">Hello, jQuery!</p>
      <button id="updateButton">Update Message</button>
    </div>
    
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
    $(document).ready(function() {
      $('#updateButton').click(function() {
        $('#message').text('Hello, World!');
      });
    });
    </script>
    

总结对比

声明式UI

  1. 描述问题的解决方案:声明式UI更关注描述问题的解决方案,而不是指定实现步骤。你告诉系统你想要什么,而不是告诉它如何做。
  2. 更接近自然语言:声明式UI的代码更像是自然语言描述,更容易理解。你描述了你想要的结果,而不是告诉计算机如何去做。
  3. 隐藏实现细节:你不需要关心底层的实现细节或者代码的执行顺序,系统会自动处理。
  4. 例子:React中的JSX是一个典型的声明式UI的例子。你描述了UI的结构和行为,React负责将其转换为实际的界面。

命令式UI

  1. 指定实现步骤:命令式UI更关注指定实现步骤,告诉计算机如何执行操作以达到预期的结果。
  2. 直接操作DOM:通常需要直接操作DOM元素,以实现所需的UI效果。
  3. 更加繁琐:通常需要编写更多的代码来描述每一个操作的细节,可能导致代码更加繁琐和难以维护。
  4. 例子:使用原生JavaScript直接操作DOM元素的代码就是命令式UI的典型例子。

区别

  • 抽象程度:声明式UI更抽象,更关注描述问题的解决方案,而命令式UI更具体,更关注实现细节。
  • 可读性:声明式UI通常更易于理解和阅读,因为它更接近自然语言描述。而命令式UI可能需要更多的注释和解释来理解代码的作用。
  • 维护性:声明式UI通常更易于维护,因为它隐藏了底层的实现细节。而命令式UI可能需要更多的细节调整和修正,以适应变化。

总的来说,声明式UI更倾向于描述问题的解决方案,而命令式UI更倾向于指定实现步骤。具体通过UI的编写和视图更新方式的不同来体现。

FlutterUI

UI视图=声明式UI+状态。Flutter框架是声明式UI,状态驱动页面变化。

下面从UI描述形式和状态驱动两方面来距离说明Flutter框架的声明式。

UI描述形式,通过描述 UI 的属性和结构来定义UI本身:

// 声明式UI
Widget testText() {
  return const Text(
    'Hello World',
    textDirection: TextDirection.ltr,
    style: TextStyle(
      fontSize: 32,
      color: Colors.black87,
    ),
  );
}

状态驱动,通过 setState修改数据来更新视图:


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;
  
  // 通过 setState修改数据来更新视图
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        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),
      ),
    );
  }
}

状态管理

广义上来讲,一个应用的状态就是当这个应用运行时存在于内存中的所有内容。这包括了应用中用到的资源,所有 Flutter 框架中有关用户界面、动画状态、纹理、字体以及其他等等的变量。这个对于状态广义的定义是有效的,但是它对于构建一个应用来说并不是很有用。

首先,你不需要管理一些状态(例如纹理),框架本身会替你管理。所以对于状态的更有用的定义是 “当任何时候你需要重建你的用户界面时你所需要的数据”。其次,你需要自己 管理 的状态可以分为两种概念类型:短时 (ephemeral) 状态和应用 (app) 状态

短时状态和应用状态

所谓状态就是构建用户界面的数据,比如文本显示的文案、图片显示的url、按钮是否显示的变量等等。状态的本质就是数据,也可以叫数据管理,只是“状态”这个词更强调了数据的变化性和动态性,以及对应用程序行为和外观的影响,更有助于理解数据不是静态的,而是随着时间和用户的操作变化的,另外,状态管理还强调了对数据变化的控制和管理,包括状态的更新、传递和持久化等方面,涉及到一些列数据的操作和逻辑处理,因此叫“状态管理”更合适。

声明式UI的核心就是数据驱动UI。开发的关注点在状态(数据)上,当我们改变状态时,用户界面会自动重新构建。所谓状态管理,就是管理应用程序中数据的变化

在Flutter中,把需要管理的状态分为两类:

  • 短时状态(Ephemeral state),单个页面、单个组件、单个Widget中的状态,widget树中其他部分不需要访问这种状态,本身是孤立的,也称局部状态页面状态,当页面消失时,该状态即消失,一般使用StatefulWidget中的setState管理。
    // 在 StatefulWidget 中使用 setState 修改数据更新UI
    // _counter时一个短时状态
    setState(() {
      _counter++;
    });
    
  • 应用状态(App state),多个页面、多个组件、多个Widget之间共享的一个状态,也称共享状态全局状态,比如:登录信息、购物车等。这种状态需要用到状态管理库来管理。

状态选择

两种状态选择的依据流程:

Flutter状态管理-基础概念

当我们就 React 的 setState 和 Redux 的 Store 哪个好这个问题问 Redux 的作者 Dan Abramov 时, 他如此回答:

“经验原则是: 选择能够减少麻烦的方式

一般来说,需要共享的应用状态就需要使用状态管理机制进行管理,在页面/组件/widget内部的短时状态使用setState管理即可。基本原则就是使用尽可能减少麻烦的方式。

可能某个状态开始是短时状态,使用setState管理,随着业务的复杂需要重构为应用状态,使用状态管理机制来管理。

转载自:https://juejin.cn/post/7375386125814448166
评论
请登录