質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.32%
Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

tailwindcss

tailwindcssとは、Webサイト・Webアプリケーションを作成するためのCSSフレームワークの一つ。ユーティリティファーストな点が特徴です。汎用的なクラスが多数用意されており、独自のデザインを自由に組み立てることができます。

Q&A

0回答

196閲覧

Firebaseから得た入力が重複して表示されてしまう。/不足しているコードがあれば教えてください!

Elle

総合スコア0

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

tailwindcss

tailwindcssとは、Webサイト・Webアプリケーションを作成するためのCSSフレームワークの一つ。ユーティリティファーストな点が特徴です。汎用的なクラスが多数用意されており、独自のデザインを自由に組み立てることができます。

0グッド

1クリップ

投稿2025/03/30 07:59

編集2025/03/31 08:55

実現したいこと

ブックマーク一覧が一つだけ表示されるようにしたい。

発生している問題・分からないこと

Firebase Firestoreに保存されているブックマーク済みの投稿データを取得し、そのデータをまとめて表示するために書いたコードです。以下の画像参照していただければ分かる通り、同じ内容のブックマーク一覧が何回も繰り返し表示されるようになってしまいました。
イメージ説明
イメージ説明

該当のソースコード

"use client"; import { auth } from "@/firebase/firebase"; import { db } from "@/firebase/firebase"; import { collection, query, where, getDocs } from "firebase/firestore"; import { useState, useEffect } from "react"; import MusicCard from "@/components/MusicCard"; export default function BookmarksPage() { const [bookmarks, setBookmarks] = useState([]); const [userId, setUserId] = useState(null); useEffect(() => { // ユーザーの認証状態の変更を監視 const unsubscribe = auth.onAuthStateChanged((user) => { if (user) { console.log("ユーザーがログインしています", user.uid); setUserId(user.uid); // ユーザーがログインしたらユーザーIDを保存 } else { console.log("ユーザーがログアウトしています"); setUserId(null); // ログアウトしたらユーザーIDをnullに } }); // クリーンアップ return () => unsubscribe(); }, []); // 初回のみ実行 useEffect(() => { // ユーザーIDがセットされたときにブックマークを取得 if (userId) { const fetchBookmarks = async () => { try { const bookmarksQuery = query( collection(db, "bookmarks"), where("userId", "==", userId) ); const bookmarkSnapshot = await getDocs(bookmarksQuery); const fetchedBookmarks = bookmarkSnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })); console.log("取得したブックマーク:", fetchedBookmarks); setBookmarks(fetchedBookmarks); // 取得したブックマークをステートにセット } catch (error) { console.error("ブックマークの取得に失敗しました:", error); } }; fetchBookmarks(); } }, [userId]); // userIdが変わるたびに実行 return ( <div className=" flex flex-col items-center justify-center min-h-screen bg-cover bg-center" style={{ backgroundImage: 'url("/images/white_00115.jpg")' }} // 背景画像を設定 > {bookmarks.length > 0 ? ( bookmarks.map((bookmark) => ( <MusicCard key={bookmark.id} music={bookmark} /> )) ) : ( <p className="text-4xl font-bold items-center justify-center mb-35 text-black"> ブックマークされた投稿が表示されるまでしばらくお待ちください…… </p> )} </div> ); }
import { useState, useEffect } from "react"; import { db } from "@/firebase/firebase"; import { collection, query, orderBy, onSnapshot } from "firebase/firestore"; import { useRouter } from "next/navigation"; import { doc, deleteDoc } from "firebase/firestore"; export default function BookmarksPage() { const [bookmarkedPosts, setBookmarkedPosts] = useState([]); const router = useRouter(); useEffect(() => { const q = query(collection(db, "bookmarks"), orderBy("createdAt", "desc")); const unsubscribe = onSnapshot(q, (snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { setBookmarkedPosts((prev) => [...prev, { ...change.doc.data(), id: change.doc.id }]); } if (change.type === "modified") { setBookmarkedPosts((prev) => prev.map((post) => post.id === change.doc.id ? { ...change.doc.data(), id: change.doc.id } : post ) ); } if (change.type === "removed") { setBookmarkedPosts((prev) => prev.filter((post) => post.id !== change.doc.id)); } }); }); return () => unsubscribe(); }, []); const handleDeleteBookmark = async (bookmarkId) => { try { const bookmarkDocRef = doc(db, "bookmarks", bookmarkId); await deleteDoc(bookmarkDocRef); alert("ブックマークを削除しました!"); } catch (error) { console.error("削除エラー:", error.message); } }; return ( <div className="p-4 space-y-4 min-h-screen"> <h2 className="text-3xl font-bold text-black"> ブックマーク一覧</h2> <div className="space-y-3"> {bookmarkedPosts.map((post) => ( <div key={post.id} className="flex flex-col w-370 border p-4 rounded-md bg-white"> <h4>{post.title}</h4> <p>{post.comment}</p> <p>{post.artist?.name || "アーティスト未選択"}</p> {post.artist?.imageUrl && ( <img src={post.artist.imageUrl} alt={post.artist.name} className="w-20 h-20 rounded-full mt-2" /> )} <a href={post.url} target="_blank" rel="noopener noreferrer" className="text-blue-500"> {post.url} </a> <div className="mt-2"> <button onClick={() => handleDeleteBookmark(post.id)} className="ml-340 w-20 bg-red-500 text-white px-4 py-2 rounded" > Delete </button> </div> </div> ))} </div> <button onClick={() => router.push("/")} className="ml-170 bg-blue-500 hover:bg-blue-800 text-white px-4 py-2 rounded mt-4" > ホームに戻る </button> </div> ); }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

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

補足

ブックマークをすればするほど、同じデータを持ったブックマーク一覧の個数が増えていきます。
画像では3つブックマークしたので、ブックマーク一覧は3つ。4つブックマークしたら、一覧は4つ……と増えていきます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.32%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問