概要
今回はfirebaseに投稿情報を加える機能を実装します。
以下投稿時のウェブアプリとfirebaseの動きです。
開発環境
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の設定を行います。
操作後 パネルビューが表示されていることを確認します。
Storageを始める
以下の手順でStorageを始めます。
操作後、Storageの作成が完了していることを確認します。
画面を実装する
画像アップロード機能を加える input type="file"のUIを隠すため useRefを使う
画像アップロード後、Xボタンを押して画像を削除することができる
firebaseに投稿情報を加える
コード部分
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
firebase
addDoc
updateDoc 画像ファイルがある場合、投稿情報に画像のパスを加える
uploadString 文字列から画像をアップロードする
その他
Udemy
- Send data to firebase and add loading effect
githubコミット分