Flutter Widget 复用完整总结(终极版)

974 阅读3分钟

*� Flutter Widget 复用完整总结(终极版)


🎯 1. StatelessWidget stl )是否会复用?

*� 结论: StatelessWidget 实例不会复用,但 Element 可能会复用!

* StatelessWidget setState() 时的行为

  • Flutter 不会复用 StatelessWidget ,每次 setState() 后都会重新创建 Widget 实例
  • 但是**StatelessWidget 的 Element 并不会被销毁,而是复用**
  • Flutter 只是用新的 StatelessWidget 来替换 Element 中的 oldWidget

✅ 示例

class StaticText extends StatelessWidget {
  StaticText() {
    print("❗StaticText 被创建了!");
  }

  @override
  Widget build(BuildContext context) {
    print("🔄 StaticText.build() 被调用了!");
    return const Text("Hello World");
  }
}

🚀 点击按钮 setState()

setState(() {});

📢 日志输出

❗StaticText 被创建了!  <-- `StatelessWidget` 重新创建
🔄 StaticText.build() 被调用了!  <-- `build()` 重新执行

📌 StatelessWidget 本身被销毁并重新创建,但 Element 不变!


🎯 2. StatefulWidget stf )如何复用?

*� 结论: StatefulWidget 不会复用,但 State Element ****可以 复用!

* StatefulWidget setState() 时的行为

  • StatefulWidget 本身会被销毁并重新创建
  • 但是 State 不会被销毁,它会在 Element 中复用
  • Flutter 只是让 State build() 重新执行,不会创建新的 State

✅ 示例

class Counter extends StatefulWidget {
  Counter() {
    print("❗Counter 被创建了!");
  }

  @override
  _CounterState createState() {
    print("🎯 CounterState 被创建了!");
    return _CounterState();
  }
}

class _CounterState extends State<Counter> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    print("🔄 Counter.build() 被调用了!");
    return Column(
      children: [
        Text("计数器: $count"),
        ElevatedButton(
          onPressed: () {
            setState(() {
              count++;
            });
          },
          child: const Text("增加"),
        ),
      ],
    );
  }
}

🚀 点击按钮 setState()

🔄 Counter.build() 被调用了!

📢 日志输出

❗Counter 被创建了!
🎯 CounterState 被创建了!   <-- `State` 只会创建一次
🔄 Counter.build() 被调用了! <-- `build()` 重新执行

📌 StatefulWidget 本身被销毁并重新创建,但 State 复用了!


🎯 3. Element StatefulWidget StatelessWidget 中的作用

* Element setState() 时如何复用

  1. Flutter 主要依赖 Element 树来管理 Widget ,而不是 Widget 树
  2. 如果 runtimeType Key 没有变,Flutter 会复用 Element
  3. 如果 Widget 类型发生了变化,Flutter 会销毁旧 Element ,创建新 Element

✅ 示例

@override
Widget build(BuildContext context) {
  return toggle ? Container() : SizedBox(); // `runtimeType` 变了,Element 无法复用!
}

📢 点击 setState() 触发切换

Container() → SizedBox()   <-- `runtimeType` 不同,不能复用 `Element`

✅ 正确写法(保证 Element 复用)

@override
Widget build(BuildContext context) {
  return Container(
    key: ValueKey("same-widget"),  // 🌟 添加 Key,保证 `Element` 复用
    child: Text("Hello"),
  );
}

📢 现在即使 setState() ,Flutter 也不会销毁 Element ,而是复用它!


🎯 4. runtimeType Key 如何帮助复用?

*� 结论:Flutter 复用 Widget 主要依赖 runtimeType Key

  • runtimeType 相同,Flutter 可以 复用
  • Key 相同,即使 Widget 位置变化,Flutter 仍然 可以 复用
  • runtimeType 不同,Flutter 无法 复用 Element ,会创建新的

✅ 示例

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      toggle ? Container() : SizedBox(),  // ❌ `runtimeType` 不同,不能复用 `Element`
    ],
  );
}

* Key Widget 复用,即使位置发生变化

@override
Widget build(BuildContext context) {
  return Column(
    children: toggle
        ? [MyWidget("A", key: ValueKey("A")), MyWidget("B", key: ValueKey("B"))]
        : [MyWidget("B", key: ValueKey("B")), MyWidget("A", key: ValueKey("A"))], 
  );
}

📢  Key 后,Flutter 仍然可以复用 Element ,提高性能!


🔥 最终总结(修正后的版本)

行为StatelessWidget (stl)StatefulWidget (stf)
Widget 是否会复用?❌ Widget 每次 build() 都会新建❌ Widget 每次 build() 都会新建
Element 是否会复用?✅ 如果类型和 Key 没变,Element 仍然复用✅ Element 仍然复用
State 是否会复用?❌ 没有 State,无法复用✅ State 会复用,不会被销毁
setState() 触发时的行为创建新 Widget,但 Element 可能复用创建新 Widget,但 State 仍然保持,Element 复用
如何优化?✅ const 避免新实例的创建✅ Key 确保 State 复用

📌 最重要的知识点

1️⃣ StatelessWidget 和 StatefulWidget 每次 build() 触发都会新建 Widget 对象,但 Element 可能被复用
2️⃣ StatelessWidget 的 Element 只要 runtimeType 和 Key 没变,Flutter 就会尝试复用!
3️⃣ StatefulWidget 的 State 只要 runtimeType 和 Key 没变,就不会被销毁,会复用!
4️⃣ const 关键字主要优化 Widget 实例的创建,并不直接影响 Element 复用
5️⃣ 使用 Key 可确保 State 复用,避免不必要的重建


✨ *� 这就是 Flutter Widget 复用的完整解析!!!  🚀🚀🚀