我想创建一个具有
authentication service
的应用程序,根据用户角色具有不同的权限和功能(例如消息)。
因此,我创建了一个用于用户和登录管理的
Provider
,另一个用于用户可以看到的消息。
现在,我想在用户登录时获取消息(一次)。在
Widgets
中,我可以通过Provider.of<T>(context)
访问提供程序,我想这是一种Singleton
。但是我如何从另一个类(在本例中是另一个提供者)访问它?
感谢您的回答。与此同时,我用另一种解决方案解决了这个问题:
在
main.dart
文件中,我现在使用 ChangeNotifierProxyProvider
而不是 ChangeNotifierProvider
来表示依赖的提供程序:
// main.dart
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => Auth()),
ChangeNotifierProxyProvider<Auth, Messages>(
builder: (context, auth, previousMessages) => Messages(auth),
initialBuilder: (BuildContext context) => Messages(null),
),
],
child: MaterialApp(
...
),
);
现在,当登录状态更改并通过身份验证提供程序时,将重建消息提供程序:
class Messages extends ChangeNotifier {
final Auth _authProvider;
List<Message> _messages = [];
List<Message> get messages => _messages;
Messages(this._authProvider) {
if (this._authProvider != null) {
if (_authProvider.loggedIn) fetchMessages();
}
}
...
}
从 version >=4.0.0 开始,我们需要采取与 @updatestage 的回答稍有不同的做法。
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => Auth()),
ChangeNotifierProxyProvider<Auth, Messages>(
update: (context, auth, previousMessages) => Messages(auth),
create: (BuildContext context) => Messages(null),
),
],
child: MaterialApp(
...
),
);
在 ChangeNotifierProxyProvider 的构造函数中传递另一个提供程序可能会导致您丢失状态,在这种情况下您应该尝试以下操作。
ChangeNotifierProxyProvider<MyModel, MyChangeNotifier>(
create: (_) => MyChangeNotifier(),
update: (_, myModel, myNotifier) => myNotifier
..update(myModel),
);
class MyChangeNotifier with ChangeNotifier {
MyModel _myModel;
void update(MyModel myModel) {
_myModel = myModel;
}
}
很简单:第一个Provider提供一个类的实例,例如:
LoginManager
。另一个提供MessageFetcher
。在 MessageFetcher
中,无论您有什么方法,只需向其添加 Context
参数并通过提供新的上下文来调用它即可。
也许你的代码看起来像这样:
MessageFetcher messageFetcher = Provider.of<ValueNotifier<MessageFetcher>>(context).value;
String message = await messageFetcher.fetchMessage(context);
在
MessageFetcher
你可以拥有:
class MessageFetcher {
Future<String> fetchMessage(BuildContext context) {
LoginManager loginManager = Provider.of<ValueNotifier<LoginManager>>(context).value;
loginManager.ensureLoggedIn();
///...
}
}
使用 Riverpod 似乎会容易得多,尤其是将参数传递到
.family
构建器以使用提供程序类作为许多不同版本的千篇一律的想法。
为什么不直接将上下文传递给提供者的构造函数,并在提供者内部使用该上下文,如下所示???
///in your main provider config...
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => MyProvider(context),
),
ChangeNotifierProvider(
create: (_) => MyProviderB(),
),
],
///in your provider...
class MyProvider with ChangeNotifier {
BuildContext context;
MyProvider(this.context);
myFunction(){
var data = this.context.read<MyProviderB>().data;
///some more code here...
}
}