개발 기간
2023/05/03 ~ 2023/06/07
개발한 트위터 웹 링크
https://imdaxsz.github.io/twitter
계기
React와 TypeScript 강의를 듣고 난 후, 작은 프로젝트를 만들어봐야겠다고 생각했다. 그런 생각을 하던 찰나 Nomad Corder(노마드 코더)에서 React + Firebase로 트위터를 클론 코딩하는 강좌를 발견하게 되었다. Firebase는 학부 시절에도 백엔드로 종종 사용했던 적이 있었고(거의 기억이 나지 않았지만), 아직은 프론트엔드에 좀 더 집중하고 싶었기 때문에 백엔드는 최대한 쉽고 가볍게 하고 싶다는 생각이 있었다. 그래서 이 강좌를 수강하며 Firebase를 React에서 사용하는 방법을 배우고, 아직은 익숙하지 않은 React도 온전히 혼자 프로젝트를 해보기 전에 다시 한번 복습해보고자 했다. 완강 후엔 좀 더 실제 트위터처럼 기능들과 UI/UX를 추가하며 한 달 동안 추가 개발을 하게 되었다.
후기
개발 기간으로 약 2주 정도를 생각하고 있었다. 최대가 3주이지 않을까..라는 생각을 했었는데 정말 나 자신을 과대평가했던 것 같다. 그리고 개념을 아는 것과 그것을 적용하는 것에는 큰 차이가 있다는 걸 다시 한번 많이 느꼈다. 생각보다 작은 것들에도 시간이 오래 걸려 개발 기간이 길어졌다. 개발 기간이 길어지고 머릿 속에서 떠올렸던 것처럼 기능이 동작하지 않을 때 힘들기도 하고 그만하고 싶다, 이 기능은 포기할까? 하는 생각도 가끔 했다. 하지만 비록 클론 코딩 강좌에서 시작했을지언정 React, TS를 공부하고 나서 하게 된 첫 개인 프로젝트라 시간이 오래 걸리더라도 꼭 하고자 했던 기능들은 다 완성하고 싶었다. 그렇게 한 달 하고 조금의 시간이 걸려 어느 정도 만족하는 결과물을 얻게 되었다.
개인적인 만족과 별개로 부족한 부분들이 꽤 보인다. 추후에 다시 개선하고 새로운 기능들을 추가해볼 수 있으면 좋겠다. 또한 state 관리를 비롯하여 React에 대해 깊은 공부가 필요한 것 같다.
어려웠던 부분 & 되짚어볼 부분
1. Firestore와 useEffect
Firestore에서 트윗 또는 사용자의 정보를 읽어오고 이를 적절한 시기와 주기로 렌더링을 해주어야 하는데 이게 은근히 어려웠던 것 같다. Firestore에서 데이터를 가져올 수 있는 방법에는 getDoc(s)와 onSnapshot이 있는데 get 방식은 그저 한 번 데이터를 가져오는 것이기 때문에 데이터의 내용을 update 했을 때 새로고침을 해야 update 된 정보를 받아볼 수 있다. 이와 달리 onSnapshot은 update 된 데이터를 새로고침 없이 실시간으로 받아볼 수 있다.
개발을 하면서 어떤 부분은 실시간 업데이트가 되길 원했고, 어떤 부분은 특정 페이지에 접속할 때 한 번만 업데이트 되길 원했다. 코드를 짜면서 이럴 때 onSnapshot이 호출되면 좋겠다, 이럴 때 getDocs가 호출되면 좋겠다 하고 useEffect를 사용했다. 근데 어떨 때는 너무 많은 호출로 오류가 발생하기도 하고, 어떨 때는 아예 호출이 안 되기도 하고, 어떨 때는 호출은 됐는데 state에 반영이 되지 않기도 했다. useEffect의 dependency가 내 생각보다 아주 중요하고 큰 영향을 미친다라는 걸 알게 되었다. 어떤 코드에선 dependency를 특정 배열 타입 state의 길이로 할 때가 있었고, 어디에선 배열 그 자체로 할 때가 있었는데 이 둘의 차이도 굉장했다. dependency를 정할 땐 아주 신중해야 한다는 걸 느꼈다.
또 새롭게 알았던 건, 나는 라우터가 파라미터를 가지고 있을 때 파라미터가 바뀌면 컴포넌트가 새롭게 렌더링 되며 mount 될 줄 알았다. 그래서 useEffect에 dependency로 빈 array를 주면 파라미터가 변할 때마다 실행될 거라고 생각했는데 그렇지 않았다..!! dependency에 파라미터를 넣어 파라미터가 변할 때마다 실행되도록 하였더니 정상적으로 잘 작동하였다.
처음 컴포넌트가 렌더링 될 때는 mount 되지만, props나 state가 변경되어 렌더링 될 때는 mount 되지 않는다는 걸 생각할 때 파라미터의 변경도 후자와 같은 느낌인 건가 하는 생각이 든다. 아시는 분 댓글로 알려주시면 감사하겠습니다.
2. Firestore 복합 색인 등록 / 복합 쿼리
query를 통해 특정 데이터들을 Firestore에서 가져오고자 할 때, 등호 연산자(==)와 부등호 연산자(<, <=, >, !=)를 결합할 경우 복합 색인 등록이 필요하다. 색인을 등록하지 않고 복합 쿼리를 사용할 경우 개발자 도구의 콘솔에서 오류를 띄워준다. 오류 속에는 링크가 포함되어 있는데 링크를 누르면 위 사진 속 색인 등록 페이지로 이동해 친절하게 색인 셋팅까지 해주며 색인을 추가할 거냐고 물어봐준다.. 나의 경우 사용한 연산이 대부분 같음(==), 같지 않음(!=)이었기 때문에 오름차순/내림차순이 크게 상관이 없었던 것 같다. 트윗의 생성 시기와 같이 정렬이 필요한 경우엔 신경 쓰도록 하자.
이유는 잘 모르겠지만 where을 통해 연산이 다른 두 가지 조건을 부여하였을 때, 두 번째 필드에 대해서는 orderBy를 넣어줘야 오류 없이 작동하였다. 처음에는 필드가 달라서인가 했는데 검색 쿼리에도 필요했던 것을 보면 연산 종류의 문제인가 싶기도 하다. (공식 문서에서 서로 다른 필드에 같은 등호 연산을 수행하였을 때는 복합 색인 등록이나 orderBy 추가가 필요하지 않았다.)
+) Firestore의 쿼리만으로는 완벽한 검색 기능을 구현할 수 없다! Third Party를 이용해야 한다. 위의 코드로는 특정 키워드로 시작하는 또는 일치하는 결과만 얻을 수 있다.
+) 생각보다 쿼리의 제한 사항이 꽤 있었다. 자세한 사항은 아래 링크로 확인하자
https://firebase.google.com/docs/firestore/query-data/queries?hl=ko#query_limitations
3. state 관리
일부 state(ex. 사용자 정보)가 많은 컴포넌트에서 사용되기도 하고, props drilling이 일어나는 경우도 있어 Redux를 이용해 상태관리를 하였다. Redux를 couter와 같은 아주 작은 예제에만 적용해 봤다가 프로젝트에 적용하니 어려운 부분도 있었다. 사용하면서도 이게 맞나... 이렇게 하면 효율적으로 state를 다룰 수 있는 게 맞나 하는 생각이 가끔 들기도 했다. 이번에 개발을 진행하면서 어떻게 해야 state를 효율적으로 관리할 수 있을까에 대한 고민이 많이 생겼다. 다른 분들의 글을 많이 찾아보며 공부해야겠다.
4. 모바일 웹 개발에서의 CSS
크롬 개발자도구의 device toolbar로 모바일 화면을 보며 열심히 코딩을 하고... 이젠 된 것 같다하고 빌드를 했는데 이게 웬 걸 일부 요소의 배치나 크기들이 분명 노트북으로 봤을 땐 괜찮았는데 실제 폰으로 보니 이상하게 나왔다. ㅠㅠ
어떤 것들은 단순 실수에 의한 것들이 있었지만 어떤 것들은 구글링이 필요했다. 가장 큰 이슈들이 수직 정렬, 수직 스크롤 등 세로 길이와 관련된 것들이었다. 편하다는 이유로 100vw, 100vh를 많이 사용했는데 pc에서는 잘 동작하나 모바일에서 문제가 된 것이다. 특히 100vh는 스크롤바가 생기게 한다. ios safari 브라우저의 경우, 상단의 노치와 url바 혹은 하단의 툴바로 인해 화면의 크기(viewport)를 실제 보여지는 윈도우 innerHeight보다 크게 잡아 100vh로 설정 시 스크롤이 생기게 된다고 한다.
CSS를 작성할 때, 모바일에서 어떻게 보여질지도 고려해서 단위 및 크기를 정해야 할 것 같다.
개발에서 도움이 된 References
1. progress bar
2. image cropper + 압축 처리
3. firestore 검색
4. 모바일 스크롤 및 수직 중앙 배치
5. 페이지 배포 시 BrowserRouter와 관련된 이슈 해결