一个例子直观的告诉你flutter中key的作用

笔者之前是java后端开发,转flutter之后又被公司裁员,当时对flutter知之甚少,去面试没看面经遂被第一题考倒:flutter中widget的key有什么作用?

查阅了网上很多描述都不太理解,最近在某视频学习网站看了一个讲解视频才略有了解。

没有key的情况下

先上代码,以下代码自定义了组件Box,Box中用GestureDetector包裹了一个有定义颜色的Container,每点击Box一次就会使的里面的数字+1.

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

void main() {
  runApp(
    MaterialApp(
      home: MyHome(),
    ),
  );
}

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

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            Box(Colors.red),
            Box(Colors.yellow),
            Box(Colors.blue),
          ],
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  const Box(this.color); // 接收并传递 key
  final Color color;

  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _counter++;
        setState(() {});
      },
      child: GestureDetector(
        onTap: () {
          _counter++;
          setState(() {});
        },
        child: Container(
          width: 80,
          height: 80,
          color: widget.color,
            child: Text("$_counter"),
          ),
      ),
    );
  }
}

把以上代码运行起来,再从上往下依次点击1、2、3次,我们会得到这么一个页面

此时我们再把_MyHomeState中的builder方法里的Box(Colors.yellow)注释掉,再hot reload一下,各位读者可以猜下页面会变成什么样

js 复制代码
class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            Box(Colors.red),
            // Box(Colors.yellow),
            Box(Colors.blue),
          ],
        ),
      ),
    );
  }
}

如果各位读者像我一样对flutter的key不甚了解,可能会认为,页面上从上往下依次是:红1、蓝3,然而页面变成了这样

为什么会变成这样呢,这正是因为没有指定key导致的。如下图所示,我们在创建widget树的时候也会创建对应的element树,而状态是保存在elemnet树中的

当我们删除了黄色的box之后,蓝色的box就顺理成章上移动一格,匹配到右边的的state = 2的box element。而state = 3的boxelement因为找不到对应的widget也被释放掉了。

正是因为上图所说没匹配到的elemnet被释放了,我们如果把之前注释的代码加回来,再hot reload一下,得到的不是红1、黄2、蓝3,而是红1、黄2、蓝0(初始值为0)

添加了key的情况下

简单修改代码(26、27、28、37行),给Box传递参数key

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

void main() {
  runApp(
    MaterialApp(
      home: MyHome(),
    ),
  );
}

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

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            Box(Colors.red, key: ValueKey(1),),
            Box(Colors.yellow, key: ValueKey(2),),
            Box(Colors.blue, key: ValueKey(3),),
          ],
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  const Box(this.color, {super.key});
  final Color color;

  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _counter++;
        setState(() {});
      },
      child: GestureDetector(
        onTap: () {
          _counter++;
          setState(() {});
        },
        child: Container(
          width: 80,
          height: 80,
          color: widget.color,
          child: Text("$_counter"),
        ),
      ),
    );
  }
}

运行程序,从上往下分别点击1、2、3次,得到红1黄2蓝3

此时再把黄色的box注释掉,hot reload一下,就会得到红1蓝3,符合我们的预期

这是因为加了key之后,widget和element不再通过顺序匹配了,而是通过key来匹配,所以这次是key=2的element被释放了

相关推荐
程序员老刘2 天前
跨平台开发地图 | 2026年6月
flutter·ai编程·客户端
悟空瞎说3 天前
Flutter 架构详解:新手必懂底层原理
flutter
SoaringHeart3 天前
Flutter最佳实践:IM聊天文字链接自动识别跳转
前端·flutter
恋猫de小郭3 天前
KMP / CMP 鸿蒙版本 Beta 发布,他有什么特别之处?
android·前端·flutter
风华圆舞4 天前
Flutter + 鸿蒙 Intents Kit:页面直达能力的完整接入方案
flutter·ui·华为·harmonyos
韩曙亮4 天前
【Flutter】Flutter 组件 ④ ( 组件渲染 的 三棵树理论 | Widget 树 → Element 树 → RenderObject 树 )
flutter·element·widget·renderobject
恋猫de小郭4 天前
Android 17 正式版发布,全新 AI 和各种破坏性更新
android·前端·flutter
kingbal4 天前
Windows:flutter环境搭建
windows·flutter
911hzh4 天前
Flutter MethodChannel 跨端通信框架 zh_native_channel:快速入门、优势分析与 Pigeon 对比
flutter
911hzh4 天前
Flutter 快速搭建新项目:用 Flutter Foundation Kit 一条命令生成带基础架构的 App 模板
flutter