前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >『Flutter』有无状态组件

『Flutter』有无状态组件

原创
作者头像
杨不易呀
发布2024-01-17 21:22:54
2543
发布2024-01-17 21:22:54
举报
文章被收录于专栏:Flutter18Flutter18

1.前言

说一下背景,就是我们在编写 Flutter 程序的时候,我们目前是将所有的代码都编写在一个文件中,现在代码量比较少所以看上去还好,但是当代码量比较大的时候,这样的代码就会显得非常的臃肿,不利于我们的维护。

那么了解了这些背景内容之后,那么官方是如何解决这个问题的呢?

2.正文

首先我们来看看官方给我们的示例代码,先将多余的注释代码给删除,然后在来看,通过观察可以发现官方是编写了一个 MyApp 类,继承了 StatelessWidget(组件类)。

在Flutter中,组件(Widgets)是构建用户界面的基本元素。组件分为两种类型:有状态组件(Stateful Widgets)和无状态组件(Stateless Widgets)。

2.1.无状态组件(Stateless Widgets)

  • 无状态组件是不可变的,意味着它们的属性不能改变, 所有的值都是最终的。
  • 通常用于当你需要展示的UI不依赖于对象内部状态时。

示例代码:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Stateless Widget'),
        ),
        body: Center(
          child: Text('Hello, Flutter!'),
        ),
      ),
    );
  }
}

2.2.有状态组件(Stateful Widgets)

  • 有状态组件可以在其生命周期中改变状态。
  • 通常用于当UI可以在用户交互或其他因素影响下改变时。

示例代码:

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Stateful Widget'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('You have pushed the button this many times:'),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

3.无状态组件

在我们之前的示例代码中,我们在 runApp 中是直接编写组件的,现在我们将组件单独抽离出来,然后在 runApp 中引用,通过继承 StatelessWidget 来实现无状态组件。

如下图是之前的代码:

现在我们将组件抽离出来,开始改造:

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

void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // 应用程序的标题,显示在任务管理窗口中。
        title: "my App",
        // 应用程序的主题,用于定义颜色,字体和阴影等。接受一个 ThemeData 对象
        theme: ThemeData(primarySwatch: Colors.blue),
        // 应用的首页
        home: Scaffold(
            appBar: AppBar(
              backgroundColor: Colors.blue,
              title: const Text('首页'),
              centerTitle: true,
            ),
            body: const Center(
              child: Text(
                'Hello Flutter',
                style: TextStyle(fontSize: 20.0),
              ),
            )
        )
    );
  }
}

运行结果:

如上代码,我们将组件抽离出来,然后在 runApp 中引用,通过继承 StatelessWidget 来实现无状态组件。

通过我的观察 MaterialApp 中的 home 属性是一个 Scaffold 组件,所以我们将 Scaffold 组件也抽离出来,然后在 MaterialApp 中引用。

代码语言:js
复制
class MyHome extends StatelessWidget {
  const MyHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.blue,
          title: const Text('首页'),
          centerTitle: true,
        ),
        body: const Center(
          child: Text(
            'Hello Flutter MyHome',
            style: TextStyle(fontSize: 20.0),
          ),
        )
    );
  }
}

运行结果:

body 中的内容是一个 Center 组件,所以我们将 Center 组件也抽离出来,然后在 Scaffold 中引用, 这里我就不浪费时间了因为本次还有一个有状态组件还要介绍无状态组件的使用就到这里了。

在深入了解有状态组件之前,先尝试利用无状态组件管理状态,看看能否实现预期效果。在此之前,也要提醒大家注意无状态组件中的一个重要事项。然后再深入了解有状态组件。

首先创建了一个名为 MyHomeTwo 的组件,其构建函数返回了一个 Center 组件。在 Center 组件的子组件中,使用了 Row 组件,并在 Row 的 children 属性中放置了一个 Checkbox。这样做是为了利用 Checkbox 的选中状态来测试是否能够修改状态。

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        // 应用程序的标题,显示在任务管理窗口中。
        title: "my App",
        // 应用程序的主题,用于定义颜色,字体和阴影等。接受一个 ThemeData 对象
        theme: ThemeData(primarySwatch: Colors.blue),
        // 应用的首页
        home: const MyHome());
  }
}

class MyHome extends StatelessWidget {
  const MyHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.blue,
          title: const Text('首页'),
          centerTitle: true,
        ),
        body: MyHomeTwo());
  }
}

class MyHomeTwo extends StatelessWidget {
  var isCheck = true;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        children: [Checkbox(value: isCheck, onChanged: (val) {
          print(val);
          this.isCheck = val is bool;
          print(this.isCheck);
        })],
      ),
    );
  }
}

运行结果:

从效果图中可以看到我们的 isCheck 一直输出的是 true,我已经通过 this.isCheck = val is bool; 这个代码重新赋值了,但是还是没有改变,这是为什么呢?

这里需要强调无状态组件中的一个关键注意事项, 在无状态组件中,组件被创建之后会将组件中的变量变成 final 的,所以无法管理状态。

那么我们该如何解决这个问题呢?这里就需要用到有状态组件了。

4.有状态组件

在我之前的介绍有状态的组件,是不是继承了 StatefulWidget 就是成为了有状态的组件了。

好,那么我们就编写一个类,创建 MyStateful 类,继承 StatefulWidget:

代码语言:js
复制
class MyStateful extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    throw UnimplementedError();
  }
}

发现要求实现 createState 方法,返回一个 State 对象,先不看返回什么,先来看,我们能不能像无状态组件那样定义一个变量就可以直接在组件中使用了就成为了一个有状态的组件了。

我的答案是不行的:在有状态组件中,组件被创建之后也会将组件中的变量变成 final 的, 这里就需要用到 State 了。

4.1.State

State 是一个抽象类,它定义了一个 State 的子类应该实现的接口。那么我就编写一个属于 MyStateful 的 State 类,继承 State,然后再将之前的 Checkbox 组件放到 MyStatefulState 中。

代码语言:js
复制
class MyStatefulState extends State {
  var isCheck = true;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        children: [
          Checkbox(
              value: isCheck,
              onChanged: (val) {
                print(val);
                this.isCheck = val as bool;
                print(this.isCheck);
              })
        ],
      ),
    );
  }
}

在 MyStateful 类 createState 方法中返回 MyStatefulState 对象:

代码语言:js
复制
class MyStateful extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyStatefulState();
  }
}

运行结果:

从效果图中可以看到 isCheck 的值已经改变了,但是呢还有一个问题就是我们的数据改变了页面 UI 没有改变,这是为什么呢?

这里就需要用到 setState 方法了。因为 Flutter 和 React 一样,都是通过数据驱动 UI 的,所以当我们的数据改变了,我们需要通过 setState 方法来通知 Flutter 重新构建 UI。

4.2.setState

setState 方法是 State 类中的一个方法,它接收一个回调函数,这个回调函数会在 setState 方法调用之后立即执行,所以我们可以在这个回调函数中改变状态。

代码语言:js
复制
this.setState(() {
  this.isCheck = val as bool;
});

5.总结

5.1.无状态组件

  • 无状态组件是不可变的,意味着它们的属性不能改变, 所有的值都是最终的。
  • 通常用于当你需要展示的UI不依赖于对象内部状态时。
  • 实现方式:继承 StatelessWidget,然后在 build 方法中返回一个 Widget。
  • 无状态组件中的变量在组件被创建之后会将组件中的变量变成 final 的。

5.2.有状态组件

  • 有状态组件可以在其生命周期中改变状态。
  • 通常用于当UI可以在用户交互或其他因素影响下改变时。
  • 在有状态组件中,组件被创建之后也会将组件中的变量变成 final 的。
  • 采用数据驱动 UI 的方式,当数据改变时,通过 setState 方法通知 Flutter 重新构建 UI。
  • 实现方式:继承 StatefulWidget,然后在 createState 方法中返回一个 State 对象。在 State 对象中定义变量,然后通过 setState 方法改变变量的值,最后在 build 方法中使用变量。(State 就相当于我们普通的一个类了)

End

  • ?如果您对本文有任何疑问或想法,请在评论区留言,我将很乐意与您交流。
  • ?您的每一条评论对我都至关重要,我会尽快给予回复。
  • ?如果您觉得这篇文章对您有所启发或帮助,请不吝赞赏、收藏或分享。
  • ?您的每一个动作都是对我创作的最大鼓励和支持。
  • ?谢谢您的阅读和陪伴!

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.前言
  • 2.正文
    • 2.1.无状态组件(Stateless Widgets)
      • 2.2.有状态组件(Stateful Widgets)
      • 3.无状态组件
      • 4.有状态组件
        • 4.1.State
          • 4.2.setState
          • 5.总结
            • 5.1.无状态组件
              • 5.2.有状态组件
              • End
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
              http://www.vxiaotou.com