💛

Firestoreを使っていいね機能を実装する

2023/11/10に公開

よくある機能をつけたい

SNSアプリを作っていて、like数をカウントするいいね機能を実装することがありますよね。
どうやってつければいいのか?
List型のデータで保存する必要があって、[]の中に、["id1","id2","id3"]といった感じのデータ構造が必要です。以下のようなコレクションを作れば実現できます!

いいね機能を実装する

いいねは、一回しかつけれないので、1回だけリストにデータを増やすメソッドと、データがあったら削除するメソッドを実装します。
公式ドキュメントによると、この機能で実現できます。
https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja#update_elements_in_an_array

final washingtonRef = db.collection("cities").doc("DC");

// Atomically add a new region to the "regions" array field.
washingtonRef.update({
  "regions": FieldValue.arrayUnion(["greater_virginia"]),
});

// Atomically remove a region from the "regions" array field.
washingtonRef.update({
  "regions": FieldValue.arrayRemove(["east_coast"]),
});

公式を参考に考えた機能だと、今回はハードコーディングですけど、ドキュメントIDをリストに保存して、それをカウントして、何人にいいねされているかをカウントする機能を実装しました!

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final blogProvider = StreamProvider((ref) async* {
  final db = FirebaseFirestore.instance;
  final snapshots = db.collection('blog').snapshots();
  yield* snapshots.map((snapshot) => snapshot.docs.map((doc) => doc.data()));
});

class LikePage extends HookConsumerWidget {
  const LikePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    final blogAsyncValue = ref.watch(blogProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('LikePage')),
      body: blogAsyncValue.when(
        data: (blogs) {
          return ListView(
            children: blogs.map((blog) {
              return ListTile(
                trailing: IconButton(
                    onPressed: () async {
                      // likesフィールドにいいねをつける。いいねをつけるときは、idをつける
                      // 今回はもうしわけないけど、ハードコーディングでidをつけています🙇
                      var id = 'erafFz7Vopqfdx4C6dKV';
                      final db = FirebaseFirestore.instance;
                      final doc = db.collection('blog').doc(id);
                      // if文でlikesをつけていなかったら、つける。なかったら外す
                      if (blog['likes'].contains(id)) {
                        await doc.update({
                          'likes': FieldValue.arrayRemove([id])
                        });
                      } else {
                        await doc.update({
                          'likes': FieldValue.arrayUnion([id])
                        });
                      }
                    },
                    icon: const Icon(Icons.favorite)),
                subtitle: Row(
                  children: [
                    // trueだったら、赤色のアイコンを表示。falseだったら、グレーのアイコンを表示。三項演算子を使う
                    blog['likes'].contains('erafFz7Vopqfdx4C6dKV')
                        ? const Icon(Icons.favorite, color: Colors.red)
                        : const Icon(Icons.favorite, color: Colors.grey),
                    const SizedBox(width: 8),
                    Text(blog['likes'].length.toString()),
                  ],
                ),
                // arrayのlikesの長さを表示
                title:  Text(blog['title']),
              );
            }).toList(),
          );
        },
        error: (error, stackTrace) => Text('Error: $error'),
        loading: () => const Center(child: CircularProgressIndicator()),
      ),
    );
  }
}

こちらのコードで、importして実行するだけ。

main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:widget_cook/firebase_options.dart';
import 'package:widget_cook/liks/like_page.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const ProviderScope(child: BlogApp()));
}

class BlogApp extends StatelessWidget {
  const BlogApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BlogApp',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const LikePage(),
    );
  }
}

gif画像用意しました

最後に

今回、ざっくりとですがFirestoreに、 like数を保存と取り消しをする機能を実装してみました。海外の情報しか技術記事ない気がして、書いてみました。参考になりそうでしたら、使ってみてください。

Jboy王国メディア

Discussion