質問編集履歴

10

訂正

2025/03/31 08:55

投稿

Elle
Elle

スコア0

test CHANGED
@@ -1 +1 @@
1
- Firebaseから得た入力が重複して表示されてしまう。/回答に必要なコードがあれば教えてください!
1
+ Firebaseから得た入力が重複して表示されてしまう。/不足しているコードがあれば教えてください!
test CHANGED
File without changes

9

誤字

2025/03/31 01:58

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -1,5 +1,5 @@
1
1
  ### 実現したいこと
2
- ブックマーク一覧が重複なしで一つだけ表示されるようにしたい。
2
+ ブックマーク一覧が一つだけ表示されるようにしたい。
3
3
 
4
4
  ### 発生している問題・分からないこと
5
5
  Firebase Firestoreに保存されているブックマーク済みの投稿データを取得し、そのデータをまとめて表示するために書いたコードです。以下の画像参照していただければ分かる通り、同じ内容のブックマーク一覧が何回も繰り返し表示されるようになってしまいました。

8

誤字

2025/03/31 01:55

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -185,6 +185,6 @@
185
185
 
186
186
  ### 補足
187
187
  ブックマークをすればするほど、同じデータを持ったブックマーク一覧の個数が増えていきます。
188
- 画像では3つブックマークしたので、ブックマーク一覧は3つ。4つブックマークしたので、一覧は4つと増えていきます。
188
+ 画像では3つブックマークしたので、ブックマーク一覧は3つ。4つブックマークした、一覧は4つ……と増えていきます。
189
189
 
190
190
 

7

タイトルの訂正

2025/03/31 01:54

投稿

Elle
Elle

スコア0

test CHANGED
@@ -1 +1 @@
1
- Firebaseから得た入力が重複して表示され
1
+ Firebaseから得た入力が重複して表示されてしまう。/回答に必要なコードがあれば教えてください!
test CHANGED
File without changes

6

修正

2025/03/31 01:52

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -82,6 +82,7 @@
82
82
  );
83
83
  }
84
84
 
85
+ ```
85
86
  ```
86
87
  import { useState, useEffect } from "react";
87
88
  import { db } from "@/firebase/firebase";

5

コードの追加

2025/03/31 01:51

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -11,41 +11,84 @@
11
11
  ### 該当のソースコード
12
12
 
13
13
  ```
14
+ "use client";
15
+ import { auth } from "@/firebase/firebase";
16
+ import { db } from "@/firebase/firebase";
17
+ import { collection, query, where, getDocs } from "firebase/firestore";
14
- import { useState, useEffect, memo } from "react";
18
+ import { useState, useEffect } from "react";
19
+ import MusicCard from "@/components/MusicCard";
20
+
21
+ export default function BookmarksPage() {
22
+ const [bookmarks, setBookmarks] = useState([]);
23
+ const [userId, setUserId] = useState(null);
24
+
25
+ useEffect(() => {
26
+ // ユーザーの認証状態の変更を監視
27
+ const unsubscribe = auth.onAuthStateChanged((user) => {
28
+ if (user) {
29
+ console.log("ユーザーがログインしています", user.uid);
30
+ setUserId(user.uid); // ユーザーがログインしたらユーザーIDを保存
31
+ } else {
32
+ console.log("ユーザーがログアウトしています");
33
+ setUserId(null); // ログアウトしたらユーザーIDをnullに
34
+ }
35
+ });
36
+
37
+ // クリーンアップ
38
+ return () => unsubscribe();
39
+ }, []); // 初回のみ実行
40
+
41
+ useEffect(() => {
42
+ // ユーザーIDがセットされたときにブックマークを取得
43
+ if (userId) {
44
+ const fetchBookmarks = async () => {
45
+ try {
46
+ const bookmarksQuery = query(
47
+ collection(db, "bookmarks"),
48
+ where("userId", "==", userId)
49
+ );
50
+ const bookmarkSnapshot = await getDocs(bookmarksQuery);
51
+ const fetchedBookmarks = bookmarkSnapshot.docs.map(doc => ({
52
+ ...doc.data(),
53
+ id: doc.id
54
+ }));
55
+
56
+ console.log("取得したブックマーク:", fetchedBookmarks);
57
+ setBookmarks(fetchedBookmarks); // 取得したブックマークをステートにセット
58
+ } catch (error) {
59
+ console.error("ブックマークの取得に失敗しました:", error);
60
+ }
61
+ };
62
+
63
+ fetchBookmarks();
64
+ }
65
+ }, [userId]); // userIdが変わるたびに実行
66
+
67
+ return (
68
+ <div
69
+ className=" flex flex-col items-center justify-center min-h-screen bg-cover bg-center"
70
+ style={{ backgroundImage: 'url("/images/white_00115.jpg")' }} // 背景画像を設定
71
+ >
72
+ {bookmarks.length > 0 ? (
73
+ bookmarks.map((bookmark) => (
74
+ <MusicCard key={bookmark.id} music={bookmark} />
75
+ ))
76
+ ) : (
77
+ <p className="text-4xl font-bold items-center justify-center mb-35 text-black">
78
+ ブックマークされた投稿が表示されるまでしばらくお待ちください……
79
+ </p>
80
+ )}
81
+ </div>
82
+ );
83
+ }
84
+
85
+ ```
86
+ import { useState, useEffect } from "react";
15
87
  import { db } from "@/firebase/firebase";
16
88
  import { collection, query, orderBy, onSnapshot } from "firebase/firestore";
17
89
  import { useRouter } from "next/navigation";
18
90
  import { doc, deleteDoc } from "firebase/firestore";
19
91
 
20
- const BookmarkItem = memo(({ post, onDelete }) => {
21
- return (
22
- <div className="flex flex-col w-370 border p-4 rounded-md bg-white">
23
- <h4>{post.title}</h4>
24
- <p>{post.comment}</p>
25
- <p>{post.artist?.name || "アーティスト未選択"}</p>
26
- {post.artist?.imageUrl && (
27
- <img
28
- src={post.artist.imageUrl}
29
- alt={post.artist.name}
30
- className="w-20 h-20 rounded-full mt-2"
31
- />
32
- )}
33
- <a href={post.url} target="_blank" rel="noopener noreferrer" className="text-blue-500">
34
- {post.url}
35
- </a>
36
- <div className="mt-2">
37
- <button
38
- onClick={() => onDelete(post.id)}
39
- className="ml-340 w-20 bg-red-500 text-white px-4 py-2 rounded"
40
- >
41
- Delete
42
- </button>
43
- </div>
44
- </div>
45
- );
46
- });
47
-
48
- BookmarkItem.displayName = 'BookmarkItem';
49
92
 
50
93
  export default function BookmarksPage() {
51
94
  const [bookmarkedPosts, setBookmarkedPosts] = useState([]);
@@ -53,36 +96,31 @@
53
96
 
54
97
  useEffect(() => {
55
98
  const q = query(collection(db, "bookmarks"), orderBy("createdAt", "desc"));
56
-
57
99
  const unsubscribe = onSnapshot(q, (snapshot) => {
58
- const updatedPosts = snapshot.docs.map((doc) => ({
100
+ snapshot.docChanges().forEach((change) => {
101
+ if (change.type === "added") {
102
+ setBookmarkedPosts((prev) => [...prev, { ...change.doc.data(), id: change.doc.id }]);
103
+ }
104
+ if (change.type === "modified") {
105
+ setBookmarkedPosts((prev) =>
59
- ...doc.data(),
106
+ prev.map((post) =>
107
+ post.id === change.doc.id ? { ...change.doc.data(), id: change.doc.id } : post
108
+ )
109
+ );
110
+ }
60
- id: doc.id,
111
+ if (change.type === "removed") {
112
+ setBookmarkedPosts((prev) => prev.filter((post) => post.id !== change.doc.id));
113
+ }
61
- }));
114
+ });
115
+ });
62
116
 
63
- // ユニークなデータを取得
64
- const uniquePosts = updatedPosts.filter((value, index, self) =>
65
- index === self.findIndex((t) => t.id === value.id)
66
- );
67
-
68
- setBookmarkedPosts(uniquePosts);
69
- }, (error) => {
70
- console.error("Snapshot error:", error);
71
- });
72
-
73
- return () => {
117
+ return () => unsubscribe();
74
- unsubscribe();
75
- };
76
118
  }, []);
77
-
119
+
78
120
  const handleDeleteBookmark = async (bookmarkId) => {
79
121
  try {
80
122
  const bookmarkDocRef = doc(db, "bookmarks", bookmarkId);
81
123
  await deleteDoc(bookmarkDocRef);
82
-
83
- // ローカル状態の更新
84
- setBookmarkedPosts((prevPosts) => prevPosts.filter((post) => post.id !== bookmarkId));
85
-
86
124
  alert("ブックマークを削除しました!");
87
125
  } catch (error) {
88
126
  console.error("削除エラー:", error.message);
@@ -91,14 +129,32 @@
91
129
 
92
130
  return (
93
131
  <div className="p-4 space-y-4 min-h-screen">
94
- <h2 className="text-3xl font-bold text-black">ブックマーク一覧</h2>
132
+ <h2 className="text-3xl font-bold text-black"> ブックマーク一覧</h2>
95
- <div className="space-y-4">
133
+ <div className="space-y-3">
96
134
  {bookmarkedPosts.map((post) => (
135
+ <div key={post.id} className="flex flex-col w-370 border p-4 rounded-md bg-white">
136
+ <h4>{post.title}</h4>
137
+ <p>{post.comment}</p>
138
+ <p>{post.artist?.name || "アーティスト未選択"}</p>
139
+ {post.artist?.imageUrl && (
97
- <BookmarkItem
140
+ <img
141
+ src={post.artist.imageUrl}
98
- key={post.id}
142
+ alt={post.artist.name}
99
- post={post}
100
- onDelete={handleDeleteBookmark}
143
+ className="w-20 h-20 rounded-full mt-2"
101
- />
144
+ />
145
+ )}
146
+ <a href={post.url} target="_blank" rel="noopener noreferrer" className="text-blue-500">
147
+ {post.url}
148
+ </a>
149
+ <div className="mt-2">
150
+ <button
151
+ onClick={() => handleDeleteBookmark(post.id)}
152
+ className="ml-340 w-20 bg-red-500 text-white px-4 py-2 rounded"
153
+ >
154
+ Delete
155
+ </button>
156
+ </div>
157
+ </div>
102
158
  ))}
103
159
  </div>
104
160
  <button
@@ -110,7 +166,6 @@
110
166
  </div>
111
167
  );
112
168
  }
113
-
114
169
  ```
115
170
 
116
171
  ### 試したこと・調べたこと
@@ -128,5 +183,7 @@
128
183
 
129
184
 
130
185
  ### 補足
131
- ブックマークをすればするほど、同じデータを持ったブックマーク一覧が増えていきます。
186
+ ブックマークをすればするほど、同じデータを持ったブックマーク一覧の個数が増えていきます。
187
+ 画像では3つブックマークしたので、ブックマーク一覧は3つ。4つブックマークしたので、一覧は4つと増えていきます。
132
188
 
189
+

4

内容の追加

2025/03/30 09:12

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -128,5 +128,5 @@
128
128
 
129
129
 
130
130
  ### 補足
131
+ ブックマークをすればするほど、同じデータを持ったブックマーク一覧が増えていきます。
131
132
 
132
-

3

文法の修正

2025/03/30 08:31

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -123,7 +123,7 @@
123
123
  1Firebase onSnapShotがレンダリングの際に多重登録されてるか
124
124
  2Keyが一意であるか
125
125
  3useEffectの依存配列を確認
126
- 4再レンダリング時に再実行されるないかを確認するためにuseEffectの依存配列が [] になっているか確認(seEffectの中にconsole.logを仕込んで、コンソール上でいつ発火しているかを確認)
126
+ 4再レンダリング時に再実行されるないかを確認するためにuseEffectの依存配列が [] になっているか確認(useEffectの中にconsole.logを仕込んで、コンソール上でいつ発火しているかを確認)
127
127
  など様々な可能性を考えて修正してみましたが一向に解決しませんでした。
128
128
 
129
129
 

2

誤字

2025/03/30 08:11

投稿

Elle
Elle

スコア0

test CHANGED
File without changes
test CHANGED
@@ -2,7 +2,7 @@
2
2
  ブックマーク一覧が重複なしで一つだけ表示されるようにしたい。
3
3
 
4
4
  ### 発生している問題・分からないこと
5
- Firebase Firestoreにるブックマークされた投稿データを取得し、そのデータをまとめて表示するために書いたコードです。以下の画像参照していただければ分かる通り、同じ内容のブックマーク一覧が繰り返し表示されるようになってしまいました。
5
+ Firebase Firestoreに保存されているブックマーク済みの投稿データを取得し、そのデータをまとめて表示するために書いたコードです。以下の画像参照していただければ分かる通り、同じ内容のブックマーク一覧が何回も繰り返し表示されるようになってしまいました。
6
6
  ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2025-03-30/2162239b-419a-4344-9ee5-46fda37b5d65.png)
7
7
  ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2025-03-30/c5e36855-62ce-47cc-bf1f-26451253f0e8.png)
8
8
 

1

誤字

2025/03/30 08:09

投稿

Elle
Elle

スコア0

test CHANGED
@@ -1 +1 @@
1
- 力が繰り返しされる
1
+ Firebaseから得た入力が重複て表示される
test CHANGED
@@ -1,5 +1,5 @@
1
1
  ### 実現したいこと
2
- ブックマーク一覧が重複なしで表示されるようにしたい。
2
+ ブックマーク一覧が重複なしで一つだけ表示されるようにしたい。
3
3
 
4
4
  ### 発生している問題・分からないこと
5
5
  Firebase Firestoreにあるブックマークされた投稿データを取得し、そのデータをまとめて表示するために書いたコードです。以下の画像参照していただければ分かる通り、同じ内容のブックマーク一覧が繰り返し表示されるようになってしまいました。