Google Firebase와 React를 이용한 트위터 클론 만들기 2

Hyuno Choi·2021년 1월 31일
0
post-thumbnail

소스 코드: https://github.com/soonitoon/dwitter
"드위터" 페이지(모바일) : https://soonitoon.github.io/dwitter

이 글은 Nomad Coder"트위터 클론코딩" 강의를 바탕으로 작성되었습니다.


2021년 1월 30일 오후

지난번에 이어 트위터 클론 코딩 2편입니다.

포스트를 쓰려다 보니 가장 중요한 user 객체와 dwitte 객체에 관한 설명을 미리 하는 게 좋을 것 같다는 생각이 들었습니다. 거의 대부분의 파일에서 prop으로 이 두 객체를 받아 필요한 정보를 쓰고 있습니다.

Object

user object

App 컴포넌트의 useEffect 부분입니다. AuthService.onAuthStateChanged에서 사용자의 로그인을 감지하면 콜백 함수가 실행됩니다.

이때 콜백 함수는 매개변수 User에서 필요한 속성을 뽑아 드위터 내에서 사용하는 UserObj를 만듭니다.

UserObj에 포함되어 있는 속성으로는

  1. displayName - 네비게이션 바에서 사용자명을 표시합니다.

  2. uid - 드윗을 만들 때 유저 정보를 함께 저장합니다.

  3. updateProfile - 사용자명을 변경할 때 쓰입니다.

이렇게 세 가지가 있습니다.

user object 문제 및 수정

사실 위의 user object를 처음부터 쓰진 않았습니다. 처음에는 Firebase에서 만들어주는 커다란 user object를 그대로 코드 내에서 사용했습니다.

user object를 재정의해야 할 필요는 Profile 페이지를 만들면서 느꼈습니다.

의도한 바는 updateProfile을 통해서 Firebase에 저장되어 있는 유저 정보를 업데이트하고 setUserObj를 통해 React의 리랜더링을 노리는 것이었습니다.

문제의 원인은 Firebase에서 그대로 받아 온 user object가 React가 변화를 감지하기에 너무 크다는 것이었습니다.

이후 Firebase의 user object에서 필요한 부분만 추출한 현재의 user object를 만들게 되었습니다.

이 부분은 Profile 페이지 부분에서 더 자세히 적겠습니다.

dwitte object

dwitteObj는 DwitteFactory 컴포넌트의 onSubmit함수 내에서 만들어집니다. dwitteObj가 저장하는 속성은 다음과 같습니다.

  1. text - 본문

  2. createdAt - 만들어진 날짜. 정렬에 사용됩니다.

  3. creatorId - 만든 유저의 id. 수정 시 본인 여부 확인, 자신의 글만 모아보는 데 사용됩니다.

  4. creatorName - 드윗 상단에 표시할 이름입니다.

  5. attachmentURL - 첨부한 사진의 URL

dwitteObj의 저장 및 세부사항은 Home 화면 설명에 적겠습니다.

Home

state

Home 컴포넌트의 state는 dwittes 뿐입니다. 현재까지 Firebase에 저장되어 있는 드윗들을 불러와 배열 형태로 저장하는 변수입니다.

드윗 불러오기

useEffect에 콜백 함수로 넣어서 홈화면 렌더링 시 side-effect로 드윗을 불러오는 함수입니다.

firestore의 메소드를 사용해서 모든 드윗을 가져오는 과정을 다음과 같습니다.

  1. collection("dwitte")을 통해 dwitte 콜렉션 레퍼런스를 가져옵니다.

  2. orderBy("createdAt", "desc")를 통해 기존 쿼리를 만들어진 시각에 따라 내림차순으로(최근 순서) 정렬한 쿼리를 가져옵니다.

  3. get()대신 onSnapshot()을 사용해서 드윗의 삭제, 수정이 실시간으로 반영될 수 있도록 합니다.

  4. onSnapshot()으로 받아온 QuerySnapshot 객체에서 각각의 docs에 접근하기 위해 snapshot.docs.map()을 사용합니다.

  5. docs를 가지고 각각의 드윗 객체를 만들어줍니다. 첫 번째 속성으로 고유 id를 넣고, ES6 스프레드 연산자로 data()로 가져온 드윗 본문 내용들을 만들고자 하는 객체에 속성으로 할당합니다.

  6. 이렇게 만든 드윗 객체 리스트를 dwittes state에 저장합니다.

드윗을 불러오는 코드는 이후 프로필 컴포넌트에서 자신이 작성한 드윗만 가져올 때도 유사하게 사용합니다.

JSX

Home 컴포넌트는 두 개의 자식 컴포넌트를 가집니다. 바로 DwitteFactoryDwitte입니다.

이름 그대로 DwitteFactory 컴포넌트는 상단바에서 드윗을 적을 수 있는 Form 역할을 합니다. 그리고 Dwitte 컴포넌트는 지금까지 만들어진 드윗들을 화면에 렌더링합니다.

Dwitte Factory

state

DwitteFactory 컴포넌트의 state는 세 가지로 구성되어 있습니다. 세 state 모두 문자열을 저장합니다.

  1. dwitte - 본문을 저장합니다.

  2. attachment - 첨부파일(이미지 URL)을 저장합니다.

  3. errorMsg - 사용자가 빈 문자열을 제출했을 때 오류 메시지를 저장합니다.

밑에서 DwitteFactory 내의 함수들에 대해 설명할 때 이 state들이 구체적으로 어떻게 사용되는지 자세히 적겠습니다.

함수 구현

본문 입력 받아오기

드윗 본문을 사용자가 입력하면 변화 내용을 받아와 dwitte state에 저장하는 간단한 함수입니다.

ES6의 객체 비구조화를 활용해서 넘겨받은 event 객체에서 value를 변수로 할당했습니다. 이 valueDwitte state로 설정합니다.

이미지 파일 첨부

이미지를 첨부하는 input 태그로부터 이미지를 받아와 브라우저가 읽을 수 있는 URL로 변환해 attachment state에 저장하는 함수입니다.

역시 객체 비구조화로 가져온 files 변수 안에는 FileList 객체가 들어있습니다.

지금은 한 번에 하나의 사진만 업로드 하도록 했기 때문에 theFile이라는 변수에 항상 files[0] 값을 넣어줍니다.

다음으로 FileReaderreadAsDataURL를 이용하여 theFile 변수에 저장해두었던 파일을 브라우저가 읽을 수 있는 URL로 바꿔줍니다.

마지막으로 FileReaderonloadend를 통해 파일 읽기가 끝났을 때 그 결과를 위에서 만들었던 attachment state에 저장해줍니다.

이미지 첨부 취소

이미지 첨부를 취소하는 간단한 함수입니다. attachment state를 빈 문자열로 다시 초기화해줍니다.

사실 이 부분을 포스팅 과정에서 수정하게 되었습니다. 이미지를 첨부하고 제거하면 이미지 첨부가 안 되는 에러가 있었는데 잊어버리고 있었나봅니다...
알고보니 setAttachment(null)이라고 되어 있더군요😅
다시 한번 글쓰기의 중요성을 느낍니다.

✔️완성된 이미지 첨부부터 삭제까지의 과정입니다.

드윗 제출

DwitteFactory 컴포넌트에서 가장 중요한 함수입니다. 필요한 데이터들을 합쳐 드윗 객체를 만들어 Firebase에 저장하는 기능을 수행합니다.

함수의 길이가 긴 만큼 위에서부터 차례대로 나눠서 설명드리겠습니다.

드윗 제출 - 이미지 URL

드윗에 이미지를 포함시키는 과정을 간략하게 정리하면 다음과 같습니다.

  1. Firebase storage에 userObj.uid를 이름으로 한 폴더를 생성합니다.

  2. 그 폴더 안에 랜덤 id를 부여해서 이미지 URL 파일을 저장합니다.

  3. 저장한 이미지 URL을 다운받는 주소를 받아와 드윗 객체에 속성으로 추가합니다.

이렇게 되면 드윗 객체에서 주소를 가져오기만 하면 해당 이미지를 드윗과 함께 렌더링 해줄 수 있습니다.

위에서 설명한 부분의 코드입니다. Firebase storage의 레퍼런스를 만들고 .child()를 통해 하위 경로를 만들어줍니다.

하위 경로는 uid/랜덤id로 설정해줍니다.

랜덤 id 생성은 uuid의 라이브러리 중 랜덤 생성인 v4를 사용했습니다.

위에서 만든 레퍼런스를 putString 메소드를 사용해서 storage에 업로드 해줍니다. .putString의 두 번째 인자로는 "data_url"을 넘겨줍니다.

그리고 putString()이 반환하는 UploadTaskSnapshotresponse 변수에
저장합니다.

마지막으로 response에 저장한 객체의 레퍼런스에서 getDownLoadURL 메소드를 통해 이미지를 다운받을 수 있는 주소를 얻어 attachmentURL 변수에 저장합니다.

만약 사용자가 아무런 이미지도 업로드하지 않았다면 attachmentURL은 초기화한 값 그대로인 빈 문자열이 됩니다.

드윗 제출 - 드윗 객체

onSubmit 함수의 마지막인 드윗 객체 생성 및 제출 부분입니다.

만든 드윗 객체를 Firebase의 Cloud Firestore에 "dwitte" 콜렉션으로 추가합니다.

그리고 설정했던 모든 state를 빈 문자열로 세팅해 초기화합니다.

끝으로, 만약 사용자가 빈 문자열을 제출하면 "no dwitte!"이라는 에러 메시지를 errorMsg state로 설정해 화면에 렌더링합니다.

지금까지 구현한 것들을 가지고 만든 드윗 제출 과정입니다! 제출 후에 새로고침 없이 실시간으로 업데이트 됩니다.🔥

지금까지 DwitteFactory 컴포넌트에 설명했는데요, 다음 포스팅에서는 Home 컴포넌트의 자식 컴포넌트인 Dwitte 컴포넌트와 Navigation, Profile에 대해 작성하겠습니다.

profile
프론트엔드 웹 개발자를 목표로 하고 있습니다.

0개의 댓글