无法在此小部件上方找到正确的提供者 [英] Could not find the correct provider above this widget
问题描述
我在使用 Flutter Provider 时遇到问题...我的流程是这样的:登录用户 ID 传递给新小部件后 -> 从那里执行保存到数据库,然后重定向到新小部件(仪表板).
这是登录后小部件的代码:
返回 MaterialApp(标题:标题,主页: 脚手架(应用栏:应用栏(标题:文本(标题),),正文:列表视图(孩子们:<小部件>[容器(边距:EdgeInsets.all(8.0),孩子:卡片(形状:RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),孩子:InkWell(onTap: () {var user = Provider.of(上下文);user.savePreference(user.user.id, "Something");user.navigateToNewPage(Dashboard(), context);打印(user.user.id);},
这有效:
user.savePreference(user.user.id, "Something");
但这会导致一个问题:
user.navigateToNewPage(Dashboard(), context);
在仪表板小部件中,我正在创建:
小部件构建(BuildContext 上下文){var user = Provider.of(上下文);
在 UserRepository 中我有这个:
类 UserRepository 和 ChangeNotifier {用户用户;状态_status = Status.Uninitialized;状态获取状态=>_地位;用户获取 getUser =>用户;UserRepository.instance();未来<void>导航到新页面(小部件页面,BuildContext 上下文){Navigator.push(context, MaterialPageRoute(builder: (context) => page));}
我知道这个话题已经解决了问题,但没有找到适合我的问题.
Provider Scope
MaterialApp>提供者(屏幕 A)>屏幕 B
如果 Provider
在屏幕 A 中实例化,则在从 A → B 执行 Navigator.push
后,它将无法在屏幕 B 中访问.
为什么?
因为 Provider
是一个 InheritedWidget
并且 Navigator
在它的 Screen A context<之外使用
MaterialApp context
/代码> 范围.(请参阅下面的详细信息.)
修复
将 Provider
移动到一个共同的父级,MaterialApp 上下文
,允许屏幕 A 和 B 继承其状态/上下文.
provider(MaterialApp)>屏幕A>屏幕 B
示例
void main() {运行应用程序(我的应用程序());}class MyApp 扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){///将 MaterialApp 包装在 Provider 小部件中返回 ChangeNotifierProvider(创建:(上下文)=>ColorModel(),//← 创建/初始化你的状态模型孩子:材料应用程序(主页:屏幕A()),);}}
详情
供应商
Provider
基于InheritedWidget
.只有子小部件可以继承父小部件的状态.Provider
需要是任何想要访问提供"的小部件树的根小部件.状态对象.
导航器
Navigator.push(context)
屏幕 A 不使用屏幕 A 的context
.- 它使用来自
MaterialApp
的context
.
- 它使用来自
Navigator.push(context)
其实就是Navigator.of(context).push
Navigator.of(context)
意味着:搜索这个上下文层次结构,直到找到一个实例化导航器的上下文- 默认的
Navigator
在MaterialApp
中实例化. - 除非您明确创建/使用不同的
Navigator
,否则您使用的是默认值. Navigator
的context
就是MaterialApp
的context
.
- 默认的
- 屏幕 B 将获得那个上下文(
MaterialApp
),不是屏幕 A 的上下文.- B 是 A 的兄弟姐妹,而不是它的孩子.
- B 不从 A 继承,即使它看起来是实例化的"
context
内 A. - 屏幕 B 是
MaterialApp
context
的子,而不是屏幕 Acontext
的子. Provider
context
范围,如果在屏幕 A 中定义,则不覆盖屏幕 B
屏幕 A → B
Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenB()))
实际上是:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ScreenB()))
就像:
Navigator.of(MaterialApp).push(MaterialPageRoute(builder: (MaterialAppContext) => ScreenB()))
所以屏幕 B 在 MaterialApp context
下,不是在屏幕 A context
下,因此无法访问屏幕 A Provider
和它的 context
.
有关Provider
的类似问题,请参阅此代码示例答案.>
I have a problem using Flutter Provider... My flow is like this: After login user id is passed to new widget -> from there it preforms save to db and then it redirects to new widget (Dashboard).
And this is a code of a widget after Login:
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView(
children: <Widget>[
Container(
margin: EdgeInsets.all(8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
child: InkWell(
onTap: () {
var user = Provider.of<UserRepository>(context);
user.savePreference(user.user.id, "Something");
user.navigateToNewPage(Dashboard(), context);
print(user.user.id);
},
This works:
user.savePreference(user.user.id, "Something");
But this is causing a problem:
user.navigateToNewPage(Dashboard(), context);
In Dashboard widget I am creating this:
Widget build(BuildContext context) {
var user = Provider.of<UserRepository>(context);
And in UserRepository I have this:
class UserRepository with ChangeNotifier {
User user;
Status _status = Status.Uninitialized;
Status get status => _status;
User get getUser => user;
UserRepository.instance();
Future<void> navigateToNewPage(Widget page, BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: (context) => page));
}
I know this topic has already solved questions, but could not find anything suitable to my problem.
Provider Scope
MaterialApp
> provider(Screen A)
> Screen B
If Provider
is instantiated in Screen A, it won't be accessible in Screen B after a Navigator.push
from A → B.
Why?
Because Provider
is an InheritedWidget
and Navigator
uses MaterialApp context
outside its Screen A context
scope. (See Details below.)
Fix
Moving Provider
up to a common-parent, MaterialApp context
, allows both Screen A and B to inherit its state/context.
provider(MaterialApp)
> Screen A
> Screen B
Example
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// wrap MaterialApp in Provider widget
return ChangeNotifierProvider(
create: (context) => ColorModel(), // ← create/init your state model
child: MaterialApp(
home: ScreenA()
),
);
}
}
Details
Provider
Provider
is based onInheritedWidget
. Only child widgets can inherit parent widget's state.Provider
needs to be the root widget for any widget tree that wants access to your "provided" state object.
Navigator
Navigator.push(context)
on Screen A doesn't use thecontext
from Screen A.- It uses
context
fromMaterialApp
.
- It uses
Navigator.push(context)
is actuallyNavigator.of(context).push
Navigator.of(context)
means: search up this context hierarchy until you find a context that instantiated a Navigator- A default
Navigator
is instantiated inMaterialApp
. - Unless you explicitly create/use a different
Navigator
, you're using the default. Navigator
'scontext
is that ofMaterialApp
.
- A default
- Screen B will get that context (of
MaterialApp
), not the context of Screen A.- B is a sibling of A, not its child.
- B does not inherit from A, even though it appears "instantiated" inside
context
A. - Screen B is a child of
MaterialApp
context
, not of Screen Acontext
. Provider
context
scope, if defined in Screen A, doesn't cover Screen B
Screen A → B
Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenB()))
is actually:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ScreenB()))
which is like:
Navigator.of(MaterialApp).push(
MaterialPageRoute(builder: (MaterialAppContext) => ScreenB())
)
So Screen B is under MaterialApp context
, not under Screen A context
and therefore has no access to Screen A Provider
and its context
.
See this answer for a code sample to a similar question about Provider
.
这篇关于无法在此小部件上方找到正确的提供者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!