Flutter:StatelessWidget vs StatefulWidget — 到底该怎么选? - 指南

1. 开场:为什么要讲这个?

80% 的 Flutter 初学者都搞不清楚 “什么时候用 Stateless?什么时候用 Stateful?”

  • 写着写着就全变成 StatefulWidget。

  • 页面卡顿其实不是 Flutter 性能问题,而是 写法影响 rebuild 范围

  • Flutter 最大的思想:UI = 函数(state)


2. StatelessWidget — 无状态组件

✅ 定义

UI 仅由 外部传入的数据 决定,自身不保存状态。

特点

特性说明
无内部状态没有 setState
可 const直接复用,减少 rebuild
更轻量构建快,生命周期简单

生命周期

build()

什么时候用?

  • 页面展示 UI,不需要在本组件内改变状态

  • 数据变化靠 父组件传参 或 状态管理(Riverpod / Provider / Bloc)

示例

class UserAvatar extends StatelessWidget {
  final String url;
  const UserAvatar(this.url);
  @override
  Widget build(BuildContext context) {
    return Image.network(url);
  }
}

3. StatefulWidget — 有状态组件

✅ 定义

有一个 State 对象保存状态,需要更新 UI 时调用 setState()

特点

特性说明
自己保存状态用 setState 更新 UI
有生命周期有 init / dispose
用于交互逻辑表单、滚动、动画、输入框控制器等

生命周期(简)

createState()
initState()
didChangeDependencies()
build()   <-- 可以调用很多次
dispose()

示例:计数器

class Counter extends StatefulWidget {
  @override
  State createState() => _CounterState();
}
class _CounterState extends State {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => setState(() => count++),
      child: Text("count = $count"),
    );
  }
}

4. 关键对比

对比点StatelessWidgetStatefulWidget
是否保存状态❌ 不保存✅ 保存
UI 是否可更新✅ 外部变化可更新✅ 内部随时更新
生命周期简单拥有完整生命周期
性能与稳定性✅ 更好⚠️ 控制不好会 rebuild 太多
推荐使用场景展示型 UI交互/动画/控制器/表单等

5. 小总结:怎么选?

不要因为会 setState 就全部用 StatefulWidget。

流程图:

是否需要内部保存状态?
        └── No → StatelessWidget
        └── Yes → StatefulWidget

进一步细分:

✅ 局部状态 → Stateful
✅ 跨组件状态 → Riverpod / Bloc
✅ UI 仅依赖外部数据 → Stateless (能 const 就 const)


6. 实战:用 Stateless + Riverpod 代替 Stateful

class UserNameText extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final name = ref.watch(userProvider);
    return Text(name);
  }
}

数据和 UI 解耦:UI 变成 Stateless,状态交给 Riverpod/Bloc。

7. 常见误区与最佳实践

错误说明
✅ 全部用 Stateful太多 setState 会导致不必要的 rebuild
✅ 把 Controller 放 build() 里会不断创建/销毁,导致内存泄漏
✅ 不写 dispose()控制器没释放,会泄漏

最佳实践:

@override
void initState() {
  super.initState();
  controller = TextEditingController();
}
@override
void dispose() {
  controller.dispose();
  super.dispose();
}

8. 结论

 能 Stateless 不 Stateful
 状态尽量外置(Riverpod / Bloc)
 局部交互才用 setState

posted @ 2025-11-30 10:15  yangykaifa  阅读(5)  评论(0)    收藏  举报