1. 在flutter中实现类似Vue的自适应更新数据,而不是每次都需要setState的方式
方案一:Riverpod(目前最主流)
Riverpod 是 Provider 作者的新作,2023-2024 年火起来的。它虽然还是要调用方法更新,但配合 ref.watch 可以实现类似自动响应的体验:
//
final counterProvider = StateProvider((ref) => 0);
// 在 widget 中使用
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider); // 自动监听,变化时重建
return Text('$count');
}
}
Riverpod 的特点是编译安全、不依赖 BuildContext、支持自动销毁状态
csharp
void main() {
runApp(
// 添加这个ProviderScope
const ProviderScope(
child: MyApp(),
),
);
}
ProviderScope 就像一个全局的"状态容器",它负责存储和管理我们接下来要创建的所有Provider的状态,之所以写在根组件上是保证所有他的子组件可以共享一个状态,类似于单例,当然也可以不写,而写在其他地方,但要注意,这样的话会导致平级或者上级无法响应数据变化,一旦销毁了,子组件之间的关系也解除了。
如果要监听的数据很多,可以包装成一个对象,单独监听这个对象或者这个对象的某个属性。
kotlin
// 定义一个用户信息类
class UserProfile {
UserProfile({this.name = '', this.age = 0, this.email = ''});
String name;
int age;
String email;
}
// 用一个 provider 管理整个用户信息
final userProfileProvider = StateProvider<UserProfile>((ref) => UserProfile());
ini
final name = ref.watch(userProfileProvider.select((user) => user.name));
方案二:GetX(极简风格)
class
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
// return MaterialApp(
// title: 'Flutter Demo',
// theme: ThemeData(colorScheme: .fromSeed(seedColor: Colors.deepPurple)),
// home: const MyHomePage(title: 'Flutter Demo Home Page1223'),
// );
// 将 MaterialApp 替换为 GetMaterialApp
return GetMaterialApp(
title: 'Flutter GetX Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(), // 指向我们的新首页
);
}
}
1.为什么在顶层要用GetMaterialApp? 如果不替换,GetX 的路由和全局交互功能可能无法正常工作。但如果你只使用状态管理(Obx、.obs),不涉及路由和对话框,理论上普通 MaterialApp 也能运行(因为 Obx 依赖于 Get 的上下文,而 Get 可以通过其他方式初始化)。不过官方强烈建议替换,以享受完整的 GetX 生态。
2. 为什么是 0.obs?它背后是什么?
0.obs 是 GetX 提供的一种简洁的响应式变量创建方式 。它的本质是 Dart 扩展方法 + 响应式包装类。
.obs是 GetX 为 Dart 的基础类型(如int、String、bool、List等)添加的扩展方法。当你写0.obs时,实际上调用的是RxInt(0),它返回一个RxInt对象。RxInt继承自Rx<T>,内部维护了一个值(_value)和一个订阅者列表(_observers)。- 当你读取
.value时,RxInt会记录当前正在运行的Obx闭包(如果有的话),将其添加到订阅者列表中。 - 当你修改
.value时(比如count.value++),RxInt会遍历所有订阅者,通知它们重新执行闭包,从而更新 UI。
这种设计被称为响应式编程 (类似 Vue 的 ref 或 MobX 的 observable),通过 .obs 让普通变量变得可观察。
3. Obx(() => Text('${controller.count.value}')) 和 setState 真的是一样的吗?
完全不同! 虽然写起来确实需要明确告诉框架"我要监听 count",但背后的机制和性能表现截然不同:
相同点
- 都需要"标记"哪些数据会影响 UI(在 GetX 里是
.obs变量,在 setState 里是整个 State 的成员变量)。 - 都是响应式的------数据变化驱动 UI 更新。
方案三:信号机制(Signals)- 2025 年新趋势
尚未有稳定版本推出,dart版本需要3.5以上,目前最新的flutter稳定版本不支持
方案四:Bloc(事件驱动)
2. 关于Widget
state

获取state的方式一:通过Context获取
context对象有一个findAncestorStateOfType()方法,该方法可以从当前节点沿着 widget 树向上查找指定类型的 StatefulWidget 对应的 State 对象。
context
在子树中获取父级 widget 的一个示例:
scala
class ContextRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Context测试"),
),
body: Container(
child: Builder(builder: (context) {
// 在 widget 树中向上查找最近的父级`Scaffold` widget
Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
// 直接返回 AppBar的title, 此处实际上是Text("Context测试")
return (scaffold.appBar as AppBar).title;
}),
),
);
}
}
- 从当前
Element开始,通过parent指针依次访问每一个祖先Element。 - 对于每个祖先
Element,检查它是否是StatefulElement(即对应的widget是StatefulWidget)。 - 如果是
StatefulElement,再检查其widget的类型是否与传入的类型参数T匹配。 - 如果匹配,则返回该
StatefulElement的state属性(即State对象)。 - 如果遍历到根节点仍未找到,返回
null。
通过GlobalKey
-
给目标
StatefulWidget添加GlobalKey。scss//定义一个globalKey, 由于GlobalKey要保持全局唯一性,我们使用静态变量存储 static GlobalKey<ScaffoldState> _globalKey= GlobalKey(); ... Scaffold( key: _globalKey , //设置key ... ) -
通过
GlobalKey来获取State对象scss_globalKey.currentState.openDrawer()
GlobalKey 是 Flutter 提供的一种在整个 App 中引用 element 的机制。如果一个 widget 设置了GlobalKey,那么我们便可以通过globalKey.currentWidget获得该 widget 对象、globalKey.currentElement来获得 widget 对应的element对象,如果当前 widget 是StatefulWidget,则可以通过globalKey.currentState来获得该 widget 对应的state对象。
注意:使用 GlobalKey 开销较大,如果有其他可选方案,应尽量避免使用它。另外,同一个 GlobalKey 在整个 widget 树中必须是唯一的,不能重复。