这是我的 InheritedWidget,
class AuthViewInherited extends InheritedWidget {
const AuthViewInherited({
super.key,
required super.child,
required this.data,
});
final AuthViewProviderState data;
static AuthViewProviderState of(BuildContext context) {
final result = context.dependOnInheritedWidgetOfExactType<AuthViewInherited>();
if (result == null) {
throw Exception("Could not find AuthViewInherited");
}
return result.data;
}
@override
bool updateShouldNotify(covariant AuthViewInherited oldWidget) {
return oldWidget.data.isBottomSheetOpen != data.isBottomSheetOpen;
}
}
这是我的国课,
class AuthViewProvider extends StatefulWidget {
const AuthViewProvider({super.key, required this.child});
final Widget child;
@override
State<AuthViewProvider> createState() => AuthViewProviderState();
}
class AuthViewProviderState extends State<AuthViewProvider> {
bool isBottomSheetOpen = false;
void changeBottomSheetOpen(bool v) {
setState(() {
isBottomSheetOpen = v;
});
}
@override
Widget build(BuildContext context) {
return AuthViewInherited(data: this, child: widget.child);
}
当我像这样在我的视图中使用它时,我在第一帧中看到“false”。但是当我在AuthView中触发changeBottomSheetOpen()时我就看不到它了。当我将其更改为 updateShouldNotify => true 时它会起作用,但我不想这样做。为什么 oldWidget.data.isBottomSheetOpen != data.isBottomSheetOpen 不起作用?
class AuthView extends StatefulWidget {
const AuthView({super.key});
@override
State<AuthView> createState() => _AuthViewState();
}
class _AuthViewState extends State<AuthView> {
@override
Widget build(BuildContext context) {
final authViewProvider = AuthViewInherited.of(context);
print(authViewProvider.isBottomSheetOpen);
// I expect rebuild in here when I call **changeBottomSheetOpen(true)**, but not rebuild.
我最好的猜测是,在
AuthViewInherited
中创建的 AuthViewProviderState
仅依赖于 AuthViewProviderState
实例 (data: this
)。当 isBottomSheetOpen
更改时,AuthViewInherited
不会重建,因为它不依赖于该字段。
最快的修复方法 - 是向
AuthViewInherited
添加一个新字段以反映 isBottomSheetOpen
。换句话说,添加新的 bool
字段,并在 updateShouldNotify
中使用它。像这样的东西:
class AuthViewInherited extends InheritedWidget {
const AuthViewInherited({
super.key,
required super.child,
required this.data,
required this.someBool,
});
final AuthViewProviderState data;
// new field
final bool someBool;
static AuthViewProviderState of(BuildContext context) {
final result =
context.dependOnInheritedWidgetOfExactType<AuthViewInherited>();
if (result == null) {
throw Exception("Could not find AuthViewInherited");
}
return result.data;
}
@override
bool updateShouldNotify(covariant AuthViewInherited oldWidget) {
// add one more condition to check. Or, maybe, check only someBool.
return oldWidget.data.isBottomSheetOpen != data.isBottomSheetOpen ||
oldWidget.someBool != someBool;
}
}
并且还更新
AuthViewProviderState
:
class AuthViewProviderState extends State<AuthViewProvider> {
bool isBottomSheetOpen = false;
void changeBottomSheetOpen(bool v) {
setState(() {
isBottomSheetOpen = v;
});
}
@override
Widget build(BuildContext context) {
return AuthViewInherited(
data: this,
child: widget.child,
someBool: isBottomSheetOpen,
);
}
}
但是,在我看来,当前的选择仍然有缺点,很难理解,而且仍然容易出错。我认为最好将
AuthViewInherited
和 AuthViewProviderState
分开,这样它们就不会互相引用。为此,您可以在 State 中创建另一个 of
静态方法:
class AuthViewProviderState extends State<AuthViewProvider> {
bool isBottomSheetOpen = false;
void changeBottomSheetOpen(bool v) {
setState(() {
isBottomSheetOpen = v;
});
}
@override
Widget build(BuildContext context) {
return AuthViewInherited(
// we get rid of data parameter in InheritedWidget.
child: widget.child,
someBool: isBottomSheetOpen,
);
}
// This is new method to get AuthViewProviderState down the tree.
static AuthViewProviderState of(BuildContext context) {
final result = context.findAncestorStateOfType<AuthViewProviderState>();
if (result == null) {
throw Exception("Could not find AuthViewInherited");
}
return result;
}
}
_AuthViewState
内部的用法将如下所示:
class AuthView extends StatefulWidget {
const AuthView({super.key});
@override
State<AuthView> createState() => _AuthViewState();
}
class _AuthViewState extends State<AuthView> {
// We will create new field here and populate it in didChangeDependencies, because it's like best practice and I do not see reason to not use it :)
late bool shouldBottomSheetBeOpen;
// Here we will populate shouldBottomSheetBeOpen. read about this method in docs, but in two words: it's created specifically to use with InheritedWidget.
@override
void didChangeDependencies() {
super.didChangeDependencies();
shouldBottomSheetBeOpen = AuthViewInherited.of(context).someBool;
}
@override
Widget build(BuildContext context) {
// This line is not needed anymore that's why I commented it.
// You should use shouldBottomSheetBeOpen as a state in build method.
// final authViewProvider = AuthViewInherited.of(context);
final authViewProviderState = AuthViewProviderState.of(context);
print('isBottomSheetOpen: ${shouldBottomSheetBeOpen}');
在这种情况下,您仍然可以从
changeBottomSheetOpen()
到 AuthViewProviderState
访问 authViewProviderState. changeBottomSheetOpen()
方法,但现在您的设置将更加独立,并且更容易管理,以防您需要更新某些内容。