如何使用 StreamBuilder 监听 Firestore 中的文档更改
How to use StreamBuilder to listen for a document change in Firestore
我的目标是重构下面的代码以使用 StreamBuilder。有人建议我可以通过使用 StreamBuilder 进一步改进我的代码,但经过几天的尝试,老实说,我不知道该做什么或从哪里开始。
我希望用户界面和 Firestore 数据库对用户点击开关磁贴做出反应。 Firestore 中的布尔值应在用户单击开关时切换,开关磁贴用户界面应相应更新。
下面的代码工作得很好,但它没有使用 StreamBuilder。
在此先感谢您的帮助。
class InterestsFitnessTile extends StatefulWidget {
const InterestsFitnessTile({
Key? key,
}) : super(key: key);
@override
State<InterestsFitnessTile> createState() => _InterestsFitnessTileState();
}
class _InterestsFitnessTileState extends State<InterestsFitnessTile> {
bool isFitnessActive = true;
final String? currentSignedInUserID = Auth().currentUser?.uid;
Future<void> _updateFitnessSetting() async {
await Auth()
.userInterestsSettingsReference
.doc(currentSignedInUserID)
.update({
AuthString.fitness: isFitnessActive,
});
setState(() {
isFitnessActive = !isFitnessActive;
});
}
@override
Widget build(BuildContext context) {
return SwitchListTileSliver(
icon: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff
? Icons.thumb_down
: Icons.thumb_up,
onChanged: (value) {
final provider = Provider.of<InterestsPageProvider>(
context,
listen: false,
);
provider.updateFitnessSettings(isOn: value);
_updateFitnessSetting();
},
subTitle: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff
? const Text(
SettingsPageString.fitnessOff,
)
: const Text(
SettingsPageString.fitnessOn,
),
title: SettingsPageString.fitness,
value: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff,
);
}
}
class InterestsPageProvider extends ChangeNotifier {
bool _currentFitness = false;
bool get isFitnessTurnedOff => _currentFitness == true;
void updateFitnessSettings({required bool isOn}) {
_currentFitness = !_currentFitness;
notifyListeners();
}
}
以下是我使用 Streambuilder 的两个示例:
示例 1:
class Messages extends StatelessWidget {
const Messages({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final currentUser = FirebaseAuth.instance.currentUser!.uid;
return StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection("chat")
.orderBy("createdAt", descending: true)
.snapshots(),
builder: (ctx, snapShot) {
if (snapShot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
final chatDocs = snapShot.data!.docs;
return ListView.builder(
reverse: true,
itemBuilder: (ctx, i) => MessageBubble(
chatDocs[i]['text'],
chatDocs[i]['userName'],
chatDocs[i]['userId'] == currentUser,
chatDocs[i]['userImg'],
),
itemCount: chatDocs.length,
);
}
},
);}}
示例 2:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => CarsProvider(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, snapShot) =>
snapShot.hasData ? const HomePage() : const UserAuth(),
),
routes: {
HomePage.routeName: (_) => const HomePage(),
SearchPage.routeName: (_) => const SearchPage(),
SearchedItemDetail.routeName: (_) => const SearchedItemDetail(),
ForgotPassword.routeName: (_) => const ForgotPassword(),
AddItem.routeName: (_) => const AddItem(),
},
),
);
}
}
我的目标是重构下面的代码以使用 StreamBuilder。有人建议我可以通过使用 StreamBuilder 进一步改进我的代码,但经过几天的尝试,老实说,我不知道该做什么或从哪里开始。
我希望用户界面和 Firestore 数据库对用户点击开关磁贴做出反应。 Firestore 中的布尔值应在用户单击开关时切换,开关磁贴用户界面应相应更新。
下面的代码工作得很好,但它没有使用 StreamBuilder。 在此先感谢您的帮助。
class InterestsFitnessTile extends StatefulWidget {
const InterestsFitnessTile({
Key? key,
}) : super(key: key);
@override
State<InterestsFitnessTile> createState() => _InterestsFitnessTileState();
}
class _InterestsFitnessTileState extends State<InterestsFitnessTile> {
bool isFitnessActive = true;
final String? currentSignedInUserID = Auth().currentUser?.uid;
Future<void> _updateFitnessSetting() async {
await Auth()
.userInterestsSettingsReference
.doc(currentSignedInUserID)
.update({
AuthString.fitness: isFitnessActive,
});
setState(() {
isFitnessActive = !isFitnessActive;
});
}
@override
Widget build(BuildContext context) {
return SwitchListTileSliver(
icon: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff
? Icons.thumb_down
: Icons.thumb_up,
onChanged: (value) {
final provider = Provider.of<InterestsPageProvider>(
context,
listen: false,
);
provider.updateFitnessSettings(isOn: value);
_updateFitnessSetting();
},
subTitle: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff
? const Text(
SettingsPageString.fitnessOff,
)
: const Text(
SettingsPageString.fitnessOn,
),
title: SettingsPageString.fitness,
value: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff,
);
}
}
class InterestsPageProvider extends ChangeNotifier {
bool _currentFitness = false;
bool get isFitnessTurnedOff => _currentFitness == true;
void updateFitnessSettings({required bool isOn}) {
_currentFitness = !_currentFitness;
notifyListeners();
}
}
以下是我使用 Streambuilder 的两个示例: 示例 1:
class Messages extends StatelessWidget {
const Messages({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final currentUser = FirebaseAuth.instance.currentUser!.uid;
return StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection("chat")
.orderBy("createdAt", descending: true)
.snapshots(),
builder: (ctx, snapShot) {
if (snapShot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
final chatDocs = snapShot.data!.docs;
return ListView.builder(
reverse: true,
itemBuilder: (ctx, i) => MessageBubble(
chatDocs[i]['text'],
chatDocs[i]['userName'],
chatDocs[i]['userId'] == currentUser,
chatDocs[i]['userImg'],
),
itemCount: chatDocs.length,
);
}
},
);}}
示例 2:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => CarsProvider(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, snapShot) =>
snapShot.hasData ? const HomePage() : const UserAuth(),
),
routes: {
HomePage.routeName: (_) => const HomePage(),
SearchPage.routeName: (_) => const SearchPage(),
SearchedItemDetail.routeName: (_) => const SearchedItemDetail(),
ForgotPassword.routeName: (_) => const ForgotPassword(),
AddItem.routeName: (_) => const AddItem(),
},
),
);
}
}