Flutter如何将Provider作为参数传入通用TemplateView页面?
问题根因
你修改后无法运行主要是两个问题导致的:
- 参数名不匹配:TemplateView构造要求传入
content参数,你在路由代码中错误传入了message参数,会直接触发编译错误。 - 上下文不匹配:路由中
ChangeNotifierProvider的builder入参context是Provider的父级上下文,此时你创建的ContentView1Provider还没有挂载到这个context上,直接用这个context调用Provider.of会找不到对应Provider实例,触发运行时错误。
解决方法
两种实现方案都可以解决问题:
方案1:通过Builder获取子树上下文
在Provider子树加一层Builder获取正确的子上下文,同时调用Provider时加listen: false(点击事件属于一次性方法调用,不需要监听Provider状态变化):
case RouterName.kContentView1: return CupertinoPageRoute( builder: (context) => ChangeNotifierProvider<ContentView1Provider>( create: (BuildContext context) => ContentView1Provider(), child: Builder( builder: (childContext) => TemplateView( title: "Content 1 page", content: ContentView1(), validationMessage: () => Provider.of<ContentView1Provider>(childContext, listen: false).validation(), ), ), ) );
方案2:Consumer包裹实现(就是你补充的方案)
如果你的内容模块需要依赖Provider状态刷新,用Consumer包裹内容模块是合理的,同样要注意给validationMessage里的Provider.of加listen: false避免不必要的刷新:
case RouterName.kContentView1: return CupertinoPageRoute( builder: (context) => ChangeNotifierProvider<ContentView1Provider>( create: (BuildContext context) => ContentView1Provider(), child: Builder( builder: (childContext) => TemplateView( title: "Content 1 page", content: Consumer<ContentView1Provider>(builder :(ctx , provider , child){ return ContentView1(); }), validationMessage: () => Provider.of<ContentView1Provider>(childContext, listen: false).validation(), ), ), ) );
优化建议
你可以给所有业务内容模块的Provider定义统一的抽象父类,对TemplateView的参数做类型约束,避免后续传错方法:
// 定义抽象基类 abstract class BaseContentProvider extends ChangeNotifier { void validation(); } // 业务Provider继承实现 class ContentView1Provider extends BaseContentProvider { @override void validation() { // 实现当前内容模块的校验逻辑 } }
内容的提问来源于stack exchange,提问作者user6551314
相关产品推荐
相关产品推荐

