0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Twitter clone Part10 firebaseに投稿情報を加える

Last updated at Posted at 2023-08-15

概要

今回はfirebaseに投稿情報を加える機能を実装します。
以下投稿時のウェブアプリとfirebaseの動きです。

PostData12.gif

開発環境

OS:Windows10
IDE:VSCode

package.json
{
  "name": "",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@heroicons/react": "^1.0.6",
    "next": "12.0.9",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@types/node": "^20.4.2",
    "@types/react": "^18.2.15",
    "autoprefixer": "^10.4.2",
    "eslint": "8.8.0",
    "eslint-config-next": "12.0.9",
    "postcss": "^8.4.5",
    "tailwindcss": "^3.0.18"
  }
}

実装のポイント

firebaseのFireStore DatabaseとStorageを設定する

firestore Databaseを始める

以下の手順でfirestorebaseの設定を行います。

image.png

操作後 パネルビューが表示されていることを確認します。

image.png

Storageを始める

以下の手順でStorageを始めます。

image.png

操作後、Storageの作成が完了していることを確認します。

image.png

画面を実装する

画像アップロード機能を加える input type="file"のUIを隠すため useRefを使う

image.png

画像アップロード後、Xボタンを押して画像を削除することができる

image.png

firebaseに投稿情報を加える

image.png

コード部分

Input

Input.jsx

+import {EmojiHappyIcon, PhotographIcon, XIcon} from '@heroicons/react/outline';
import {useSession, signOut} from "next-auth/react";
+import{addDoc,collection,doc,serverTimestamp,updateDoc} from "firebase/firestore"
+import{getDownloadURL, ref, uploadString} from "firebase/storage";
+import{db, storage} from "../firebase";
+import {useState,useRef} from "react";

export default function Input(){
    const {data: session} = useSession();
+    const [input,setInput] = useState("");
+    const [selectedFile, setSelectedFile] = useState(null);
+    const [loading,setLoading] = useState(false);
+    const filePickerRef = useRef(null);

+    const sendPost = async () =>{
+        if(loading) return;
+        setLoading(true);

+        const docRef = await addDoc(collection(db,"posts"),{
+            id: session.user.uid,
+            text:input,
+            userImg:session.user.image,
+            timestamp: serverTimestamp(),
+            name: session.user.name,
+            username: session.user.username
+        });
    
+        const imageRef = ref(storage, `posts/${docRef.id}/image`);
+        if(selectedFile){
+            await uploadString(imageRef, selectedFile,"data_url").then(async() =>{
+                const downloadURL = await getDownloadURL(imageRef);
+                await updateDoc(doc(db,"posts",docRef.id),{
+                    image: downloadURL,
+                });
+            });
+        }
+    
+        setInput("");
+        setSelectedFile(null);
+        setLoading(false);
+    };

+    const addImageToPost = (e) =>{
+        const reader = new FileReader();
+        if(e.target.files[0]){
+            reader.readAsDataURL(e.target.files[0]);
+        }
+
+        reader.onload = (readerEvent) =>{
+            setSelectedFile(readerEvent.target.result);
+        }
+    }


    return(
        <>
            {session && (
                <div className="flex border-b border-gray-200 p-3 space-x-3">
                
                    <img
                        onClick={signOut}
                        src={session.user.image}
                        alt="user-img"
                        className="h-11 w-11 rounded-full cursor-pointer hover:brightness-95"
                    />
                    <div className="w-full dived-y devide-gray-200">
                        <div className="">
+                            <textarea 
+                                className="w-full border-none focus:ring-0 text-lg placeholder-gray-700"
+                                rows="2"
+                                placeholder="What`s happening?"
+                                value={input}
+                                onChange={(e) => setInput(e.target.value)}
+                            ></textarea>
                        </div>
+                        {selectedFile &&(
+                            <div className="relative">
+                                <XIcon
+                                    onClick={() => setSelectedFile(null)}
+                                    className="h-7"
+                                    />
+                                <img
+                                    src={selectedFile}
+                                    className={`${loading && "animate-pulse"}`}
+                                />
                            </div>
+                        )}
+                        <div className="flex items-center justify-between pt-2.5">   
+                        {!loading &&(
+                                <>
+                                    <div className="flex" >
+                                        <div className="" onClick={() => filePickerRef.current.click()}>
+                                            <PhotographIcon className="h-10 w-10 hoverEffect p-2 text-sky-500 hover:bg-sky-100" />
+                                            <input type="file" hidden ref={filePickerRef} onChange={addImageToPost} />
+                                        </div>
+                                        <EmojiHappyIcon className="h-10 w-10 hoverEffect p-2 text-sky-500 hover:bg-sky-100" />
+                                    </div>                                    <button onClick={sendPost} disabled={!input.trim()} className="bg-blue-400 text-white px-4 py-1.5 rounded-full font-bold">Tweet</button>                       
                                </>
                                )} 
                        </div>
                    </div>
                </div>
            )}
        </>
    )
}

参考

css

javascript

FileReader オブジェクト

FileReader.readAsDataURL()

event.target.files

Next.js

React

useRef

image.png

firebase

addDoc

image.png

updateDoc 画像ファイルがある場合、投稿情報に画像のパスを加える

image.png

uploadString 文字列から画像をアップロードする

image.png

その他

Udemy

  1. Send data to firebase and add loading effect

githubコミット分

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?