Flutter:如何在子小部件的构建上下文之外的函数中访问 'provider' 值?
Flutter: How to access 'provider' values in a function outside the build context of the child widget?
提供程序值来自父窗口小部件。我可以在构建上下文中使用提供者值。但是,我需要 getHomeCampaigns 函数中的提供商值。我尝试定义局部变量并在构建小部件后将它们分配给提供程序值,但该函数声称变量是在 null 上调用的。我猜它们是在提供商的构建上下文中设置之前使用的。
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// Variables to be set inside the function and then used by the last widget
User currentUser;
String country;
List<CampaignWidget> friendsCamps;
List<CampaignWidget> featuredCamps;
// Function that needs the provider values
getHomeCampaigns() async {
// Get all campaigns where their owner is in the list of friends for the current user
QuerySnapshot friendsSnapshot = await Firestore.instance
.collection('campaigns')
.where('user.uid', whereIn: currentUser.friends)
.where('attributes.active', isEqualTo: true)
.orderBy('created', descending: true)
.limit(20)
.getDocuments();
// Get featured campaigns documents in the current country
QuerySnapshot featuredSnapshot = await Firestore.instance
.collection('campaigns')
.where('attributes.featured', isEqualTo: true)
.where('funders.${currentUser.uid}', isEqualTo: false)
.where('country', isEqualTo: country)
.orderBy('user.rating', descending: true)
.limit(5)
.getDocuments();
// Make 2 lists of CampaignWidget out of the documents retrieved
List<CampaignWidget> campaigns = friendsSnapshot.documents
.map((doc) => CampaignWidget(campaign: Campaign.fromDocument(doc)))
.toList();
List<CampaignWidget> featured = featuredSnapshot.documents
.map((doc) => CampaignWidget(campaign: Campaign.fromDocument(doc)))
.toList();
setState(() {
// Set the featured and friends lists of CampaignWidget to the newly made lists
this.featuredCamps = featured;
this.friendsCamps = campaigns;
});
}
@override
void initState() {
super.initState();
getHomeCampaigns();
}
@override
Widget build(BuildContext context) {
this.currentUser = Provider.of<User>(context);
this.country = Provider.of<String>(context);
return Scaffold(
backgroundColor: Color(0xFFE8E8E8),
appBar: AppBar(
centerTitle: false,
title: Text("Home"),
actions: <Widget>[
/// Search users
IconButton(
icon: Icon(
Icons.search,
),
onPressed: () {},
),
],
),
body: RefreshIndicator(
onRefresh: () => getHomeCampaigns(),
child: // Some widget that uses the variables,
),
);
}
}
您可以像这样从您的提供商那里读取变量:Provider.of(context, listen: false).yourVariable
in getHomeCampaigns
。你必须有 listen: false
才能工作,因为它不在小部件树中,所以它无法在 yourVariable
更改时更新 - 请参阅 。如果这不起作用,则说明您声明提供者时出现问题。
我从 api 继承的 Widget 转变为提供者。 《The Flutter Complete Reference》建议避免使用 inheritWidget 因为复杂。我从 materialapp 开始并将其包裹在我的 api class 周围,其中包含我的 restful 调用。我使用计数器来查看按钮是否已被按下。现在,我可以在 materialapp 树中的所有对象中访问我的 api 调用。
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My app',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: Provider<Api>(
create: (context) => Api(),
child: Home(title: 'my title')));
}
}
class Home extends StatefulWidget {
Home({Key key, @required this.title}) : super(key: key);
final String title;
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _counter = 0;
onLogin(BuildContext context) {
LoginView param = new LoginView("abc@com",
"xxx");
Provider.of<Api>(context, listen: false)
.addLogin(context, param)
.then((value) {
setState(() {
_counter++;
});
}).catchError((error) {
DialogCaller.showErrorDialog(context,
error.toString()).then((value) {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Example'),
),
body: Container(
child: Column(
children: [
TextButton.icon(
label: Text("abc"),
icon: Icon(Icons.web),
onPressed: () {
onLogin(context);
setState(() {
_counter++;
});
}),
Text(
'$_counter',
style:
Theme.of(context).textTheme.headline4,
)
],
)));
}
}
你应该看看 Riverpod。它填补了提供商的注意事项,并为您提供了一系列新功能。您可以在没有上下文的情况下访问 class 中定义的 'provider' 值和函数。它还允许您拥有多个相同类型的 'providers'。
提供程序值来自父窗口小部件。我可以在构建上下文中使用提供者值。但是,我需要 getHomeCampaigns 函数中的提供商值。我尝试定义局部变量并在构建小部件后将它们分配给提供程序值,但该函数声称变量是在 null 上调用的。我猜它们是在提供商的构建上下文中设置之前使用的。
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// Variables to be set inside the function and then used by the last widget
User currentUser;
String country;
List<CampaignWidget> friendsCamps;
List<CampaignWidget> featuredCamps;
// Function that needs the provider values
getHomeCampaigns() async {
// Get all campaigns where their owner is in the list of friends for the current user
QuerySnapshot friendsSnapshot = await Firestore.instance
.collection('campaigns')
.where('user.uid', whereIn: currentUser.friends)
.where('attributes.active', isEqualTo: true)
.orderBy('created', descending: true)
.limit(20)
.getDocuments();
// Get featured campaigns documents in the current country
QuerySnapshot featuredSnapshot = await Firestore.instance
.collection('campaigns')
.where('attributes.featured', isEqualTo: true)
.where('funders.${currentUser.uid}', isEqualTo: false)
.where('country', isEqualTo: country)
.orderBy('user.rating', descending: true)
.limit(5)
.getDocuments();
// Make 2 lists of CampaignWidget out of the documents retrieved
List<CampaignWidget> campaigns = friendsSnapshot.documents
.map((doc) => CampaignWidget(campaign: Campaign.fromDocument(doc)))
.toList();
List<CampaignWidget> featured = featuredSnapshot.documents
.map((doc) => CampaignWidget(campaign: Campaign.fromDocument(doc)))
.toList();
setState(() {
// Set the featured and friends lists of CampaignWidget to the newly made lists
this.featuredCamps = featured;
this.friendsCamps = campaigns;
});
}
@override
void initState() {
super.initState();
getHomeCampaigns();
}
@override
Widget build(BuildContext context) {
this.currentUser = Provider.of<User>(context);
this.country = Provider.of<String>(context);
return Scaffold(
backgroundColor: Color(0xFFE8E8E8),
appBar: AppBar(
centerTitle: false,
title: Text("Home"),
actions: <Widget>[
/// Search users
IconButton(
icon: Icon(
Icons.search,
),
onPressed: () {},
),
],
),
body: RefreshIndicator(
onRefresh: () => getHomeCampaigns(),
child: // Some widget that uses the variables,
),
);
}
}
您可以像这样从您的提供商那里读取变量:Provider.of(context, listen: false).yourVariable
in getHomeCampaigns
。你必须有 listen: false
才能工作,因为它不在小部件树中,所以它无法在 yourVariable
更改时更新 - 请参阅 。如果这不起作用,则说明您声明提供者时出现问题。
我从 api 继承的 Widget 转变为提供者。 《The Flutter Complete Reference》建议避免使用 inheritWidget 因为复杂。我从 materialapp 开始并将其包裹在我的 api class 周围,其中包含我的 restful 调用。我使用计数器来查看按钮是否已被按下。现在,我可以在 materialapp 树中的所有对象中访问我的 api 调用。
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My app',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: Provider<Api>(
create: (context) => Api(),
child: Home(title: 'my title')));
}
}
class Home extends StatefulWidget {
Home({Key key, @required this.title}) : super(key: key);
final String title;
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _counter = 0;
onLogin(BuildContext context) {
LoginView param = new LoginView("abc@com",
"xxx");
Provider.of<Api>(context, listen: false)
.addLogin(context, param)
.then((value) {
setState(() {
_counter++;
});
}).catchError((error) {
DialogCaller.showErrorDialog(context,
error.toString()).then((value) {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Example'),
),
body: Container(
child: Column(
children: [
TextButton.icon(
label: Text("abc"),
icon: Icon(Icons.web),
onPressed: () {
onLogin(context);
setState(() {
_counter++;
});
}),
Text(
'$_counter',
style:
Theme.of(context).textTheme.headline4,
)
],
)));
}
}
你应该看看 Riverpod。它填补了提供商的注意事项,并为您提供了一系列新功能。您可以在没有上下文的情况下访问 class 中定义的 'provider' 值和函数。它还允许您拥有多个相同类型的 'providers'。