flutter_bloc 库中的存储库提供程序在推送新路由时不提供存储库
Repository provider in the flutter_bloc library doesn't provide repository with when pushing new route
我正在使用 flutter_bloc 库来构建我的应用程序。除了 BlocProvider 之外,我还使用 Repository Provider,因为我将在整个应用程序中广泛使用特定的存储库。但我在 context 方面遇到了问题。以下是我的代码片段:
main.dart
void main() async {
.......
appRepository _appRepository = AppRepository();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(
BlocProvider(
builder: (context) =>
AuthenticationBloc(appRepository: _appRepository)..dispatch(AppStarted()),
child: App(appRepository: _appRepository,),
),
);
});
}
class App extends StatelessWidget {
............
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (BuildContext context, AuthenticationState state) {
.....
if (state is AuthenticationUnauthenticated) {
return SafeArea(
top: false,
bottom: false,
child: RepositoryProvider(
builder: (context) => _appRepository,
child: LoginPage(firebaseMessaging: _firebaseMessaging),
),
);
}
......
},
),
);
}
}
在登录表单中找到注册按钮:
register_button.dart
class RegisterButton extends StatelessWidget {
final FirebaseMessaging _firebaseMessaging;
RegisterButton({
Key key,
@required FirebaseMessaging firebaseMessaging,
}) : assert(firebaseMessaging != null),
_firebaseMessaging = firebaseMessaging,
super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Don't have an account?", style: TextStyle(color: Colors.black)),
SizedBox(width: 4.0),
GestureDetector(
child: Text("Register here!",
style: TextStyle(
color: Color(0xFF585B8D), fontWeight: FontWeight.w500)),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
return RegisterPage(
firebaseMessaging: _firebaseMessaging,
);
}),
);
},
)
],
);
}
register_page.dart
class RegisterPage extends StatelessWidget {
final FirebaseMessaging _firebaseMessaging;
RegisterPage({
Key key,
@required FirebaseMessaging firebaseMessaging,
}) : assert(firebaseMessaging != null),
_firebaseMessaging = firebaseMessaging,
super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
builder: (context) => RegisterBloc(
appRepository: RepositoryProvider.of<AppRepository>(context),
firebaseMessaging: _firebaseMessaging,
),
child: RegisterForm(),
),
);
}
}
问题:
当我点击登录表单上的注册按钮时出现错误,显示如下:
No ancestor could be found starting from the context that was passed to RepositoryProvider.of<AppRepository>().
This can happen if:
1. The context you used comes from a widget above the RepositoryProvider.
2. You used MultiRepositoryProvider and didn't explicity provide the RepositoryProvider types.
Good: RepositoryProvider<AppRepository>(builder: (context) => AppRepository())
Bad: RepositoryProvider(builder: (context) => AppRepository()).
The context used was: BlocProvider<RegisterBloc>(dirty, state: _DelegateWidgetState#a87b2(lifecycle state: created))
为什么会出现此错误?如果我将存储库提供程序作为 blocprovider 的子项并将应用程序作为子存储库提供程序放在主要功能中,然后删除 App() 中的 invidual 存储库提供程序,则此问题似乎已解决。我猜问题出在从按钮按下 material 页面路由。我不认为我理解 context 或 provider 在 Flutter 中是如何工作的。我以为提供商会查找 repository/bloc 的小部件树,推送路由是否会破坏这种连续性?
当您使用 Navigator.of(context).push
或 Navigator.of(context).pushNamed
时,推送的小部件不是调用 Navigator.of(context).push
或 Navigator.of(context).pushNamed
的小部件的子项,此小部件是包含给定 context
的 Navigator
的最接近实例,在您的情况下,Navigator
是由 MaterialApp
创建的,因此如果您想提供 Repository
或Bloc
与 routes
不同,Provider
必须是 Navigator
的父级,在您的情况下必须是 MaterialApp
.
的父级
我正在使用 flutter_bloc 库来构建我的应用程序。除了 BlocProvider 之外,我还使用 Repository Provider,因为我将在整个应用程序中广泛使用特定的存储库。但我在 context 方面遇到了问题。以下是我的代码片段:
main.dart
void main() async {
.......
appRepository _appRepository = AppRepository();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(
BlocProvider(
builder: (context) =>
AuthenticationBloc(appRepository: _appRepository)..dispatch(AppStarted()),
child: App(appRepository: _appRepository,),
),
);
});
}
class App extends StatelessWidget {
............
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (BuildContext context, AuthenticationState state) {
.....
if (state is AuthenticationUnauthenticated) {
return SafeArea(
top: false,
bottom: false,
child: RepositoryProvider(
builder: (context) => _appRepository,
child: LoginPage(firebaseMessaging: _firebaseMessaging),
),
);
}
......
},
),
);
}
}
在登录表单中找到注册按钮:
register_button.dart
class RegisterButton extends StatelessWidget {
final FirebaseMessaging _firebaseMessaging;
RegisterButton({
Key key,
@required FirebaseMessaging firebaseMessaging,
}) : assert(firebaseMessaging != null),
_firebaseMessaging = firebaseMessaging,
super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Don't have an account?", style: TextStyle(color: Colors.black)),
SizedBox(width: 4.0),
GestureDetector(
child: Text("Register here!",
style: TextStyle(
color: Color(0xFF585B8D), fontWeight: FontWeight.w500)),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
return RegisterPage(
firebaseMessaging: _firebaseMessaging,
);
}),
);
},
)
],
);
}
register_page.dart
class RegisterPage extends StatelessWidget {
final FirebaseMessaging _firebaseMessaging;
RegisterPage({
Key key,
@required FirebaseMessaging firebaseMessaging,
}) : assert(firebaseMessaging != null),
_firebaseMessaging = firebaseMessaging,
super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
builder: (context) => RegisterBloc(
appRepository: RepositoryProvider.of<AppRepository>(context),
firebaseMessaging: _firebaseMessaging,
),
child: RegisterForm(),
),
);
}
}
问题:
当我点击登录表单上的注册按钮时出现错误,显示如下:
No ancestor could be found starting from the context that was passed to RepositoryProvider.of<AppRepository>().
This can happen if:
1. The context you used comes from a widget above the RepositoryProvider.
2. You used MultiRepositoryProvider and didn't explicity provide the RepositoryProvider types.
Good: RepositoryProvider<AppRepository>(builder: (context) => AppRepository())
Bad: RepositoryProvider(builder: (context) => AppRepository()).
The context used was: BlocProvider<RegisterBloc>(dirty, state: _DelegateWidgetState#a87b2(lifecycle state: created))
为什么会出现此错误?如果我将存储库提供程序作为 blocprovider 的子项并将应用程序作为子存储库提供程序放在主要功能中,然后删除 App() 中的 invidual 存储库提供程序,则此问题似乎已解决。我猜问题出在从按钮按下 material 页面路由。我不认为我理解 context 或 provider 在 Flutter 中是如何工作的。我以为提供商会查找 repository/bloc 的小部件树,推送路由是否会破坏这种连续性?
当您使用 Navigator.of(context).push
或 Navigator.of(context).pushNamed
时,推送的小部件不是调用 Navigator.of(context).push
或 Navigator.of(context).pushNamed
的小部件的子项,此小部件是包含给定 context
的 Navigator
的最接近实例,在您的情况下,Navigator
是由 MaterialApp
创建的,因此如果您想提供 Repository
或Bloc
与 routes
不同,Provider
必须是 Navigator
的父级,在您的情况下必须是 MaterialApp
.