Flutter中InheritedWidget在状态数据变更后不重建子组件的问题
嘿,看起来你碰到了InheritedWidget更新后子组件没跟着重建的问题,我先梳理下你提供的代码,再帮你排查可能的原因和解决办法。
首先先把你的代码整理出来:
你的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; } }
你的StatefulWidget及State类
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; // 这里帮你补全了默认值,你原来的代码没写完 // 建议封装一个更新状态的方法,确保调用setState void toggleBottomSheet() { setState(() { isBottomSheetOpen = !isBottomSheetOpen; }); } @override Widget build(BuildContext context) { return AuthViewInherited( data: this, child: widget.child, ); } }
接下来分析可能导致子组件不重建的原因,以及对应的解决办法:
状态更新时没调用setState:如果你直接修改
isBottomSheetOpen的值而不调用setState,那么AuthViewProvider的build方法不会重新执行,AuthViewInherited也就不会更新,子组件自然不会重建。一定要通过setState来触发状态更新,就像上面补的toggleBottomSheet方法那样。updateShouldNotify的判断逻辑不全:你现在只对比了
isBottomSheetOpen字段,如果你的子组件还依赖AuthViewProviderState里的其他数据(比如用户信息、表单状态等),那这些字段变化时,updateShouldNotify需要返回true才会触发子组件更新。比如如果有userInfo字段,就要把它也加入对比:@override bool updateShouldNotify(covariant AuthViewInherited oldWidget) { return oldWidget.data.isBottomSheetOpen != data.isBottomSheetOpen || oldWidget.data.userInfo != data.userInfo; // 新增其他字段的对比 }子组件没有正确订阅依赖:子组件必须在
build方法里调用AuthViewInherited.of(context)来获取状态,这样才能和InheritedWidget建立依赖关系。如果你只是在initState或者其他生命周期里获取一次状态,那之后的状态变更不会触发子组件重建。比如正确的子组件写法:class ExampleChildWidget extends StatelessWidget { @override Widget build(BuildContext context) { // 在build里调用of,建立依赖 final authState = AuthViewInherited.of(context); return Container( child: Text(authState.isBottomSheetOpen ? "底部弹窗已打开" : "底部弹窗已关闭"), ); } }
另外,你的of方法用了context.dependOnInheritedWidgetOfExactType,这部分是对的,这个方法会自动建立依赖关系,而如果用context.getInheritedWidgetOfExactType的话是不会订阅变化的,所以这部分不用改。
备注:内容来源于stack exchange,提问作者samedhrmn

