🚀 const 修饰的 StatelessWidget 和未修饰的区别
在 Flutter 中,const StatelessWidget 和 普通的 StatelessWidget 在 实例复用 和 性能优化 方面有很大的区别。我们从 创建机制、Element 复用、性能优化 三个方面来详细总结它们的不同。
1️⃣ const 修饰的 StatelessWidget 和 未修饰的区别
✅ const 主要作用是让 Widget 变成编译时常量,可以复用已创建的实例
| 区别 | 普通 StatelessWidget | const 修饰的 StatelessWidget |
|---|---|---|
| 实例创建 | 每次 build() 触发,都会新建 Widget 实例 | 相同的 const Widget 只会创建一次,后续复用这个实例 |
| Element 复用 | 只要 runtimeType 和 Key 相同,Element 可以复用 | 和普通 Widget 的 Element 复用规则相同! |
| 性能优化 | 每次 build() 触发都会新建对象,占用额外内存 | 复用已创建的 const Widget,节省内存,减少不必要的 Diff 操作 |
📌 结论:
const主要优化的是 Widget 实例的创建,和Element是否复用没有直接关系。- 即使
StatelessWidget不是const,但runtimeType和Key不变,它的Element仍然可能复用。 - 使用
const可以避免创建不必要的 Widget 实例,从而减少内存占用,提高性能。
2️⃣ 代码示例
❌ 普通 StatelessWidget(不使用 const,每次 build() 都会创建新的 Widget 实例)
class MyWidget extends StatelessWidget {
MyWidget() {
print("🔥 MyWidget 实例被创建");
}
@override
Widget build(BuildContext context) {
print("🔄 MyWidget.build() 被调用了");
return Text("Hello");
}
}
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
bool toggle = true;
@override
Widget build(BuildContext context) {
return Column(
children: [
MyWidget(), // 每次 `setState()` 都会创建新实例
ElevatedButton(
onPressed: () {
setState(() {}); // 没有改变 Widget 结构
},
child: Text("刷新"),
),
],
);
}
}
📢 点击 "刷新" 按钮后,日志输出
🔥 MyWidget 实例被创建 <-- 重新创建 StatelessWidget
🔄 MyWidget.build() 被调用了 <-- 重新执行 build()
✅ 每次 setState() 都会重新创建 MyWidget 实例,增加不必要的内存开销
✅ const 修饰的 StatelessWidget(会复用实例,不会重复创建)
class MyWidget extends StatelessWidget {
const MyWidget(); // 使用 const 构造函数
@override
Widget build(BuildContext context) {
print("🔄 MyWidget.build() 被调用了");
return Text("Hello");
}
}
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
bool toggle = true;
@override
Widget build(BuildContext context) {
return Column(
children: [
const MyWidget(), // 使用 const
ElevatedButton(
onPressed: () {
setState(() {}); // 没有改变 Widget 结构
},
child: Text("刷新"),
),
],
);
}
}
📢 点击 "刷新" 按钮后,日志输出
🔄 MyWidget.build() 被调用了 <-- 直接复用之前创建的实例,无需新建
✅ 即使 setState() 触发了重建,const 修饰的 MyWidget 依然不会被重复创建实例
3️⃣ const 关键点总结
是否使用 const | Widget 实例是否复用? | Element 是否复用? | 优化效果 |
|---|---|---|---|
不使用 const | 每次 setState() 都会新建 | 可能复用(如果 runtimeType 和 Key 没变) | 占用额外内存,降低性能 |
使用 const | Widget 只创建一次,后续直接复用 | 可能复用(如果 runtimeType 和 Key 没变) | 减少不必要的 Widget 创建,节省内存,提高性能 |
4️⃣ const 会影响 Element 复用吗?
🚨 不会!const 只优化 Widget 实例创建,并不会影响 Element 复用规则!
Flutter 判断 Element 是否复用的标准:
- 如果 Widget 的
runtimeType和Key没变,Element仍然可以复用 - 即使
StatelessWidget不是const,但runtimeType相同,它的Element仍然可能复用 - 如果 Widget 结构变化(
runtimeType变了或者Key变了),Flutter 才会销毁Element,创建新的
📌 总结:
const只会帮助 Flutter 复用Widget实例,而Element是否复用由runtimeType和Key决定- ✅
const+Element复用 = 更好的性能优化!
🔥 终极总结
| 特性 | 普通 StatelessWidget | const 修饰的 StatelessWidget |
|---|---|---|
| Widget 实例是否会复用? | ❌ 每次 build() 都会新建 | ✅ 只创建一次,后续复用 |
| Element 是否会复用? | ✅ 可能复用(runtimeType & Key 不变) | ✅ 可能复用(runtimeType & Key 不变) |
| 性能优化 | ❌ 每次 build() 都会新建对象,浪费性能 | ✅ 避免重复创建 Widget,节省内存,提高性能 |
🔥 最佳实践
✅ 适用 const 的情况
✔ 无状态(StatelessWidget)并且创建后不会更改的 Widget
✔ 常见的基本 UI 组件,如 Text、Icon、Container、Row、Column 等
✔ 列表项、界面静态部分等不会变动的组件
✅ 示例
const Text("Hello World"); // 推荐使用 `const`
const Icon(Icons.home); // 推荐使用 `const`
const SizedBox(height: 10); // 推荐使用 `const`
❌ 不适用 const 的情况
❌ 需要动态更新的 Widget(setState() 后会变化)
❌ 包含 StatefulWidget,因为状态会改变
Widget build(BuildContext context) {
return Text(DateTime.now().toString()); // ❌ 不能用 const,因为时间会变化
}
💡 总结:尽可能使用 const 来优化 StatelessWidget 的性能,但它不会影响 Element 复用! 🚀