纵观响应式框架开发,状态管理是一个绕不开的话题。不论是 React/Vue,还是 flutter 中,其核心思想基本一致。在 flutter 中,有以下三种基本思想:
- 组件自身管理状态(封装性高)
- 父级组件管理状态(灵活性高)
- 混合管理状态
flutter 状态管理指南:
- 用户数据交由父级管理
- widget 样式外观数据自身管理
- 如不确定该使用何种管理方式,建议使用父级管理,可以拥有极高的灵活性
demo 示例
- 自身管理
class TapBoxA extends StatefulWidget {
const TapBoxA({super.key});
@override
State<TapBoxA> createState() => _TapBoxAState();
}
class _TapBoxAState extends State<TapBoxA> {
bool _active = false;
//点击事件触发setState修改状态,进而重新渲染
void toggleActive(){
setState(() {
_active = !_active;
});
}
@override
Widget build(BuildContext context) {
//手势事件
return GestureDetector(
onTap: toggleActive,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: _active?Colors.lightGreen[400]:Colors.grey[400]
),
child: Center(
child: Text(_active?"active":"inActive"),
),
),
);
}
}
- 父级管理
class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});
@override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void toggleActive(bool newVal){
setState(() {
_active = newVal;
});
}
@override
Widget build(BuildContext context) {
return TapBoxB(active: _active, onChanged: toggleActive);
}
}
class TapBoxB extends StatelessWidget {
const TapBoxB({super.key, required this.active, required this.onChanged});4
//该active类似于Vue中computed 相应父级 active,
//为何使用final?
/**
*1. 因为当tap事件触发,则父级会重新渲染UI,意味着每次都是新的tapBoxB
*2. 子组件内不存在任何修改该状态事件,所以使用final,onChange同理
*/
final bool active;
final ValueChanged<bool> onChanged;
//onTap事件调用父级 toggleActive 事件
void _handleTap(){
onChanged(!active);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: active?Colors.lightGreen[400]:Colors.grey[400]
),
child: Center(
child: Text(active?"active":"inActive"),
),
),
);
}
}
- 混合管理
class ParentWidgetC extends StatefulWidget {
const ParentWidgetC({super.key});
@override
State<ParentWidgetC> createState() => _ParentWidgetCState();
}
class _ParentWidgetCState extends State<ParentWidgetC> {
//父级负责active状态
bool _active = false;
void toggleActive(bool newVal) {
setState(() {
_active = newVal;
});
}
@override
Widget build(BuildContext context) {
return TapBoxC(active: _active, onChanged: toggleActive);
}
}
class TapBoxC extends StatefulWidget {
const TapBoxC({super.key, required this.active, required this.onChanged});
final bool active;
final ValueChanged<bool> onChanged;
@override
State<TapBoxC> createState() => _TapBoxCState();
}
class _TapBoxCState extends State<TapBoxC> {
//子组件自己维护高亮状态
bool highLight = false;
void _handleTap() {
//在状态类中,可以使用widget获取上级
widget.onChanged(!widget.active);
}
void _handleTapDown(TapDownDetails detail) {
setState(() {
highLight = true;
});
}
void _handleTapUp(TapUpDetails detail) {
setState(() {
highLight = false;
});
}
void _handleTapCancel() {
setState(() {
highLight = false;
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
onTapDown: _handleTapDown,
onTapUp: _handleTapUp,
onTapCancel: _handleTapCancel,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: widget.active ? Colors.lightGreen[400] : Colors.grey[400],
border: highLight
? Border.all(color: Colors.lightBlue[300]!, width: 2)
: null),
child: Center(
child: Text(widget.active ? "active" : "inActive"),
),
),
);
}
}