miladtech_after_init
为有状态的小部件添加了一个 didInitState() 生命周期方法,您可以在其中安全地访问继承的小部件。
InheritedWidget 在 Flutter 框架中被广泛使用。许多状态管理包,如 ScopedModel 和 Provider 也使用它。不幸的是,InheritedWidgets 无法从 State 的 initState() 方法中访问。 Flutter 文档指出:
/// You cannot use [BuildContext.inheritFromWidgetOfExactType] from this
/// method. However, [didChangeDependencies] will be called immediately
/// following this method, and [BuildContext.inheritFromWidgetOfExactType] can
/// be used there.
此包由一个简单的 State 类 mixin 组成,它提供了一个名为 didInitState() 的新方法。它只会被调用 **一次**,在 initState() 之后,在 didChangeDependencies() 和 build() 之前。您可以从该方法中安全地访问 InheritedWidgets,并使用它们来执行小部件的任何设置任务。
方法顺序
使用此库,State 方法按以下顺序调用:
initState()didInitState()← **新增!**didChangeDependencies()build()
示例
import 'package:flutter/material.dart';
import 'package:miladtech_after_init/miladtech_after_init.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: Example(),
),
),
);
}
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> with AfterInitMixin<Example> {
Size size;
/// This gets called first, as usual.
@override
void initState() {
super.initState();
// Your code here
}
/// This gets called after initState(), only once.
/// Safely access inherited widgets here.
@override
void didInitState() {
// No need to call super.didInitState().
// setState() is not required because build() will automatically be called by Flutter.
size = MediaQuery.of(context).size;
}
/// This gets called after didInitState().
/// And anytime the widget's dependencies change, as usual.
@override
void didChangeDependencies() {
super.didChangeDependencies();
// Your code here
}
/// Finally this gets called, as usual.
@override
Widget build(BuildContext context) {
return Center(
child: Text(size.toString()),
);
}
}
这只是一个简单的例子。您通常会在 didInitState() 中执行更有用的操作,例如访问设置数据或订阅来自 InheritedWidget 的 Stream。
替代方案
initState() 限制的一个典型解决方法是延迟执行需要访问 InheritedWidget 的代码。
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
print(MediaQuery.of(context).size);
});
}
但是,这会导致您的代码在 build() 方法之后执行,这可能不是您想要的。
单元测试
此包附带单元测试,以验证 didInitState() 只被调用一次,并且 State 方法按上述顺序调用。
鸣谢
此包由 MiladTech 创建。
