我正在为社区开发一款具有登录,注册,会议和聊天功能的应用程序。成功登录后,路线将转到具有五个底部导航的主页。我正在此应用中使用Firebase进行身份验证和Firestore。
我想在Home组件启动时获取一次数据,并将数据传递给其他五个底部导航栏组件。 现在,每当在导航组件之间切换时,我都会获取数据。这会增加Firestore的读取次数。
我尝试使用构造函数变量通过组件传递数据。但这是行不通的。它显示了无法将数据传递到底部导航组件的错误。这是我的代码。
Home.dart
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
User currentUser;
String userId;
Home({this.currentUser, this.userId});
}
class _HomeState extends State<Home> {
CurrentUser userInfo;
DocumentSnapshot doc;
int _selectedIndex = 0;
List<String> upcoming_seven_days;
FirestoreService _firestoreService = FirestoreService();
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static List<Widget> _widgetOptions = <Widget>[
Dashboard(),
MeetingList(),
EventList(),
Chat(),
Profile(),
];
static const List<Widget> _appBarText = <Widget>[
Text(
'Dashboard',
style: TextStyle(
fontWeight: FontWeight.w300,
fontSize: 26,
),
),
Text(
'Meetings',
style: TextStyle(
fontWeight: FontWeight.w300,
fontSize: 26,
),
),
Text(
'Events',
style: TextStyle(fontWeight: FontWeight.w300, fontSize: 26),
),
Text(
'Chat',
style: TextStyle(fontWeight: FontWeight.w300, fontSize: 26),
),
Text(
'Profile',
style: TextStyle(fontWeight: FontWeight.w300, fontSize: 26),
),
];
@override
void initState() {
// TODO: implement initState
super.initState();
//setCurrentUserID(widget.currentUser.uid);
//setCurrentUserData(doc.data());
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: _appBarText.elementAt(_selectedIndex)),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
width: double.maxFinite,
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.dashboard),
title: Text('Dashboard'),
backgroundColor: Colors.black),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('Meetings'),
backgroundColor: Colors.black),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_view_day),
title: Text('Events'),
backgroundColor: Colors.black),
BottomNavigationBarItem(
icon: Icon(Icons.chat),
title: Text('Chat'),
backgroundColor: Colors.black),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text('Profile'),
backgroundColor: Colors.black),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.lightBlue[200],
onTap: _onItemTapped,
elevation: 8.0,
backgroundColor: Colors.black,
),
);
}
}
每当用户切换到会议列表组件时,我都将从Firestore中获取数据。我不想那样做。相反,我想将各自的数据从Home传递到其他组件。而且应该是快照,以便可以监听更改。
MeetingList.dart
class MeetingList extends StatelessWidget {
var userInfo;
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
Future getuserinfo() async {
// final uid = firebaseAuth.currentUser.uid;
// userinfo = await firestoreService.getCurrentUserInfo(uid);
// userinfo = userinfo.data().length;
// //print(userinfo);
// return uid;
final uid = firebaseAuth.currentUser.uid;
DocumentSnapshot user = await FirebaseFirestore.instance
.collection('userProfiles')
.doc(uid)
.get();
userInfo = user.data();
return userInfo;
}
@override
Widget build(BuildContext context) {
CollectionReference meetings =
FirebaseFirestore.instance.collection('meetings');
return FutureBuilder(
future: getuserinfo(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return LoadingIndicator();
} else {
return StreamBuilder<QuerySnapshot>(
stream: meetings.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return LoadingIndicator();
}
return new ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
String meetingRole = document.data()['role'];
var userRole = userInfo['role'];
print(userRole);
if (meetingRole == 'all' || meetingRole == userRole) {
return Meeting_Card(
meeting: document.data(),
);
} else {
return Container();
}
}).toList(),
);
},
);
}
},
);
}
}
您的帮助将对社区大有帮助。
答案 0 :(得分:2)
您可以为此使用Provider
软件包,它是InheritedWidget
周围的包装。
InheritedWidget
用于有效地向下传播信息 树,而不必将它们通过各种构造函数 在小部件树下。
您可以找到有关InheritedWidget
here的更多信息。
Provider
包是用InheritedWidget
包裹起来的 更易于使用和可重复使用。
文档here中有关Provider
的更多信息
使用Provider
实施解决方案:
创建一个名为ChangeNotifier
的{{1}}类,以保存要在所有子小部件之间公用的数据:
UserProvider
现在将class UserProvider extends ChangeNotifier {
User userInfo;
Future getuserinfo() async {
// final uid = firebaseAuth.currentUser.uid;
// userinfo = await firestoreService.getCurrentUserInfo(uid);
// userinfo = userinfo.data().length;
// //print(userinfo);
// return uid;
final uid = firebaseAuth.currentUser.uid;
DocumentSnapshot user = await FirebaseFirestore.instance
.collection('userProfiles')
.doc(uid)
.get();
userInfo = user.data();
return userInfo;
}
}
小部件包装在Home
小部件中:
ChangeNotifierProvider
现在,您可以使用以下方法从同一个窗口小部件树中的任意位置访问class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<UserProvider>(
lazy: false,
create: (context) => UserProvider(),
child: Home(),
);
}
}
类的内容(任何选项卡):
UserProvider
您还可以查看提供程序包中的/// Get an instance of the UserProvider in the ancestors of the current widget tree like this.
UserProvider userProvider = Provider.of<UserProvider>(context);
/// Call any method inside the UserProvider class like this
userProvider.getUserInfo();
/// access any data variables inside the UserProvider class like this.
User userInfo = userProvider.userInfo;
和Consumer
小部件,它们提供了一种基于Selector
类的某些参数来重绘UI的有效方法,从ChangeNotifier
类中调用notifyListeners()
方法时。