4일차 CSS/기능 리팩토링 및 배포 완료
작업 내용
- Complete chatroom function
- Add chat-room in each picture
- Chat function is available for logined user
- Applied CSS and CSS-Animation
- Applied Media-Query(Responsive Web for Laptop/Tablet/Mobile)
- Apply dotenv for firebase API Key
- Hide all of sensitive info in .env
- Deploy app by Firebase
배포주소: https://j-star-gram.firebaseapp.com/
chatroom.js
1) get data and render
데이터베이스에 변화가 있을때마다 새 데이터(모든 메세지데이터)를 불러오는데,
imgId === selectedImgId 즉, 선택된 사진에 관련된 메세지 데이터만 가져올 수 있도록 filter 메소드를 이용하여 필터링한다.
이를 위해서 imgId 라는 객체를 메세지 데이터에 포함시켰다. 박스안의 스트링이 자동으로 생성되는 이미지 id 이다.
import React, { useState, useEffect } from "react";
import { timeStamp } from "../firebase/config";
import styled from "styled-components";
import { motion } from "framer-motion";
import Message from "./message";
import firebase from "firebase/app";
const Chatroom = ({ user = null, selectedImgId = null }) => {
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState("");
const { uid, displayName, photoURL } = user;
const db = firebase.firestore();
useEffect(() => {
if (db) {
const unsub = db
.collection("messages")
// .where("imgId", "==", selectedImgId)
.orderBy("createdAt")
.limit(100)
.onSnapshot((snap) => {
//show recent message
const ulObj = document.getElementById("ulbox");
ulObj.scrollTop = ulObj.scrollHeight;
const data = snap.docs
.map((doc) => ({ ...doc.data(), id: doc.id })) //Each child in a list should have a unique "key" prop.
.filter((ele) => {
return ele.imgId === selectedImgId; //extract messages for the selectedImg
});
if (data.length <= 10) {
setMessages(data);
} else {
const lastTen = data.slice(data.length - 10, data.length);
setMessages(lastTen);
}
});
return unsub;
}
}, [db, selectedImgId]);
const handleOnChange = (e) => {
setNewMessage(e.target.value);
};
const handleOnSubmit = (e) => {
e.preventDefault();
if (db) {
//make specific collection for each pircture!!
db.collection("messages").add({
text: newMessage,
createdAt: timeStamp(),
uid,
displayName,
photoURL,
imgId: selectedImgId,
});
}
setNewMessage("");
// const inputBox = document.getElementById("inputBox");
// inputBox.focus();
};
이 메세지 데이터들은 아래와 같이 각 메세지 단위에 전달되어 렌더링 된다.
<Ulbox id="ulbox" style={{ listStyle: "none", paddingLeft: "0px" }}>
{messages.map((message) => (
<li id="libox" key={message.id}>
<Message
user={message}
text={message.text}
createdAt={message.createdAt}
/>
</li>
))}
</Ulbox>
2) submit new message
새 메세지를 제출하면 handleOnSubmit 함수를 통해 데이터베이스에 저장된다.
const handleOnSubmit = (e) => {
e.preventDefault();
if (db) {
//make specific collection for each pircture!!
db.collection("messages").add({
text: newMessage,
createdAt: timeStamp(),
uid,
displayName,
photoURL,
imgId: selectedImgId,
});
}
setNewMessage("");
// const inputBox = document.getElementById("inputBox");
// inputBox.focus();
};
3) user info (App.js)
현재 유저로 상태를 유지하되 변화가 생기면 새로운 user 로 상태를 저장하거나 null 로 설정한다.
const [user, setUser] = useState(() => auth.currentUser);
useEffect(() => {
//this detects the change on state of user login
const unsubscribe = auth.onAuthStateChanged((user) => {
if (user) {
setUser(user);
} else {
setUser(null);
}
if (initializing) {
setInitializing(false);
}
});
//cleanup subscription(the state of login of user to logout)
return unsubscribe;
}, [initializing, auth]);
이 user 라는 객체 안에 아래의 정보가 담기는데, uid/displayname/photoURL 은 자동으로 포함되어 있다.
Overview
오늘의 생각
파이어베이스를 활용한 부분(firestore/storage/auth(googlelogin)/deployment),
상태관리(createdAt/text/displayname/photoURL/imgId) 그리고 Framer-motion 활용법 등에 대한 코드리뷰를 해야겠다.
파이어베이스 기능들을 사용해보고자 3-4일 동안 진행했던 단기 프로젝트여서 조금 정신없이 코드를 짰던 것 같다.
필요한 부분이 있다면 로직 리팩토링도 해야겠다. 개괄적으로나마 파이어베이스를 백엔드 파트로 활용하는 법을 익힐 수 있었다.
가능하면, 그동안 진행했던 프로젝트들의 기능을 좀 더 손봐야겠다.
그리고, 내 포트폴리오 웹사이트를 하나 만들어야겠다.
추후 추가할 기능
- 무한 스크롤
- 채팅창에 접속 유저 표시
- 메시지 입력중 말풍선 효과
- 채팅창 첫 렌더시 최신 글이 먼저 보이도록 수정
- 사진 저장 기능(버튼)
- 카테고리 및 검색 기능
도움받은 사이트
파이어베이스 배포: youtu.be/IDHfvpsYShs