트위터 클론코딩

김성현·2021년 7월 1일
0

강의

목록 보기
6/9

React, Firebase

1 SETUP

firebase 설치

npm i firebase

firebase 설정

import firebase from 'firebase/app'

const firebaseConfig = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_AUTH_DOMAIN,
    projectId: process.env.REACT_APP_PROJECT_ID,
    storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_MESSAGIN_ID,
    appId: process.env.REACT_APP_APP_ID,
}

export default firebase.initializeApp(firebaseConfig)

.env파일에 아래와 같은 형태로 저장해야지 create-react-app에서 환경변수로 접근이 가능하다. 이 과정은 단순히 key가 git에 올라가는것만 방지함

REACT_APP_"KEY_NAME"=value

import 절대경로사용

// jsconfig.json
{
    "compilerOptions": {
        "baseUrl": "src"
    },
    "include": ["src"]
}

2 AUTHENTICATION

2.0 Using Firebase Auth

export const authService = firebase.auth()

2.3 Creating Account

  • Promise를 반환함으로 async await사용
  • try catch문 사용
try {
  if(회원가입) {
    await authService.createUserWithEmailAndPassword(email, password);
  if(로그인) {
    await authService.signInWithEmailAndPassword(email, password);
  }
} catch(error){
  setError(error.message);
}

에러처리

const [error, setError] = useState("");
/* ... */
{error && <span className="authError">{error}</span>}

Persistence: 사용자들을 어떻게 기억할 것인지 선택
개발자도구 - Application - IndexedDB

firebase.auth.Auth.Persistence.Type
  • LOCAL : 브라우저를 닫아도 사용자 정보 기억
  • SESSION : 현재 탭에서 사용자 정보 기억
  • NONE : 정보 기억x, 새로고침시 로그아웃

2.4 Log In

새로고침시 로그아웃되는 문제 해결

  • init state생성
  • useEffect로 초기화
const [init, setInit] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);

useEffect(() => {
    authService.onAuthStateChanged((user) => {
      if(user){
        setIsLoggedIn(true);
      }
      setInit(true);
    });
  }, []);

return (
  <>
    {init ? <AppRouter isLoggedIn={isLoggedIn} /> : "Initializing..."}
  </>
)

2.5 Social Login

provider 생성 후 popup

// 구글 provider
const provider = new firebase.auth.GoogleAuthProvider();
// 깃헙 provider
const provider = new firebase.auth.GithubAuthProvider();

await authService.signInWithPopup(provider);

2.6 Log Out

로그아웃 및 리다이렉션

const history = useHistory();
const onLogOutClick = () => {
    authService.signOut();
    history.push("/");
};

3 NWEETING

firebase database 설정

import 'firebase/firestore'

export const dbService = firebase.firestore()

Create

await dbService.collection("tweets").add(tweetObj);

Read(Realtime)

await dbService.collection("tweets").onSnapshot((snapshot) => {
  const tweetArray = snapshot.docs.map((doc) => ({
    id: doc.id,
    ...doc.data()
    }));
  setTweets(tweetArray);
});

Update

await dbService.doc(`tweets/${tweetObj.id}`).update(tweetObj);

Delete

await dbService.doc(`tweets/${tweetObj.id}`).delete();

4 FILE UPLOAD

사진 업로드

const [attachment, setAttachment] = useState("");

// 파일 선택
const onFileChange = (event) => {
    const {target: {files}} = event;
    const theFile = files[0];
    const reader = new FileReader();
  
    // 이벤트 리스터 추가
    reader.onloadend = (finishedEvent) => {
        const {currentTarget: {result}} = finishedEvent;
        setAttachment(result);
    };
  
    // 파일 읽기
    reader.readAsDataURL(theFile); 
};

// 파일 삭제
const onClearAttachment = () => {
        setAttachment("");
};

return(
<>
  <input type="file" accept="image/*" onChange={onFileChange} />
  {attachment && (
    <>
      <img src={attachment} />
      <button onClick={onClearAttachment}>Clear</button>
    </>
  )}
</>
)

firebase storage 저장

import 'firebase/storage'

export const storageService = firebase.storage()
// 파일에 대한 reference 생성
const attachmentRef = storageService.ref().child(`${userObj.uid}/${uuidv4()}`);
// 파일 내용 업데이트(reference에 파일 정보 담기)
const response = await attachmentRef.putString(attachment, "data_url");
// 접근가능한 URL 생성
const attachmentUrl = await response.ref.getDownloadURL();

uuidv4: 이미지 이름을 랜덤으로 생성하기 위한 랜덤 식별자 생성 라이브러리

npm i uuid
import { v4 as uuidv4 } from "uuid";

uuidv4() // 랜덤 식별자 생성

firebase storage 삭제

await storageService.refFromURL(tweetObj.attachmentUrl).delete();

5 EDIT PROFILE

firebase에서 내정보 불러오기(쿼리사용)

const getMyTweets = async() => {
    const tweets = await dbService
        .collection("tweets")
        .where("creatorId", "==", userObj.uid)
        .orderBy("createdAt")
        .get();
  
     console.log(tweets.docs.map((doc)=>doc.data()));
};

firebase는 NoSQL이여서 쿼리 사용시 쿼리에 대한 복합 인덱스를 생성해주어야한다.

user객체 크기 경량화

{
  displayName: user.displayName,
  uid: user.uid,
  updateProfile: (args) => user.updateProfile(args)
}

이유: 변경되는 객체의 크기가 크다면 react의 리렌더링 기능이 동작하지 않을 수 있다.

profile
JS개발자

0개의 댓글