如何使用 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(),
        },
      ),
    );
  }
}