dwitter 1.0.1 패치

Hyuno Choi·2021년 8월 6일
0
post-thumbnail

2021년 8월 6일

늘 새로운 시리즈의 포스팅만 하다가 오랜만에 예전에 만들었던 dwitter 프로젝트의 저장소를 클론받아 작업을 시작했습니다. 처음에는 새로운 기능을 추가할 생각이었으나, 콘솔창에 뜨는 수두룩한 오류와 경고 메시지들을 보고는 깨끗한 콘솔창을 만드는 것을 목표로 삼았습니다.

브라우저 지원 범위 설정

$ npm start 를 통해 리엑트 리엑트 스크립트를 실행하고 가장 먼저 뜬 메시지는 이것이었습니다.

Greetings, time traveller. We are in the golden age of prefix-less CSS, where Autoprefixer is no longer needed for your stylesheet.

시간여행자라고 시작하는 문장이 참 인상적인데요🙃 이제 prefix-css 는 더 이상 필요하지 않으니 Autoprefixer 를 쓰지 말라고 합니다. 혹시나 하고 스타일시트들을 이곳저곳 살펴봤더니 프리픽서가 하나 달려있는 속성이 있어 제거해주었으나 여전히 같은 메시지가 떴습니다.

결국 해당 메시지를 기반으로 구글링을 한 결과, browserslist 라는 모듈이 문제의 원인인 것 같습니다. 정확히 말하자면, 해당 모듈에 넘겨준 쿼리가 문제였습니다. 덕분에 browserlist의 존재에 대해서도 알게 되었습니다. browserlist 는 최신 자바스크립트 코드나 프레임워크를 빌드할 때 지원 브라우저를 간편하게 설정해줄 수 있는 모듈입니다.

지원 브라우저는 package.json 에서 쿼리로 설정합니다. 여기서 지원 브라우저의 범위를 너무 느슨하게 잡은 탓에 구형 브라우저 버전으로 빌드될 때 Autoprefixer 가 작동한 것 같습니다. 그렇다면 해결 방법은 브라우저 리스트의 쿼리의 기준을 강화하면 될 것입니다.

브라우저 지원 기준을 다음과 같이 수정했습니다.

  • 시장 점유율 0.3% 이상
  • 인터넷 익스플로러 지원 안 함
  • 2년 이상 지원 끊긴 브라우저 지원 안 함
  • 오페라 미니 지원 안 함

이제 $ npx browserslist 명령어를 입력하면 해당 쿼리를 통과한 브라우저 목록을 볼 수 있습니다.

and_chr 92
and_uc 12.12
android 4.4.3-4.4.4
chrome 91
chrome 90
chrome 89
edge 91
firefox 89
firefox 88
ios_saf 14.5-14.7
ios_saf 14.0-14.4
ios_saf 13.4-13.7
opera 76
safari 14.1
safari 14
safari 13.1
samsung 14.0

img 태그에 alt 속성 추가

이제 다음 경고 메시지입니다.

img elements must have an alt prop, either with meaningful text, or an empty string for decorative images

img 태그에 alt 속성을 붙이고 최소한 빈 문자열이라도 넣으라고 합니다. 이전까지 img 태그의 속성 중 하나인 alt 는 그저 이미지를 불러오는 데 실패했을 때 뜨는 글자 정도인 줄 알았습니다. 그런데 경고 메시지까지 띄워 알려줄 정도면 제가 간과하고 있는 중요성이 있을 것 같아 구글링을 해봤습니다.

alt 속성을 왜 신경써서 작성해야 하는지에 대해 자세하게 설명해놓은 글이 있어 중요한 부분만 요약했습니다. 이 링크가 원문입니다: https://moz.com/learn/seo/alt-text

웹에서 접근성은 중요한 가치입니다. 장애를 가지고 있다 하더라도 웹의 정보에 접근 가능해야 합니다. 특히 시각장애인의 경우 페이지 리더를 통해 웹 문서의 정보를 듣게 되는데, 이때 이미지 태그 대신 읽히는 것이 alt 속성에 적힌 텍스트입니다. 실제로 W3C 홈페이지의 Accessibility 문서에 들어가보면 이 부분에 대해 굉장히 강조하고 있습니다.

또한 alt는 검색 엔진과 크롤링에서 이미지를 선택하고 분류하는 데 요긴하게 쓰이기도 합니다.

alt 속성의 텍스트를 적는 요령에 대해서도 정리되어 있긴 하나, 한 마디로 요약할 수 있을 것 같습니다.

이미지가 들어가는 자리를 모두 alt 텍스트로 대치하더라도 문서의 의미가 똑같이 전달되어야 합니다.

원칙적으로 alt 텍스트는 이미지의 의미를 글로 전달해야 하며, 빈 문자열이나 단순히 키워드를 적어서는 안 됩니다.

드위터에서는 이미지 설명을 이미 드윗의 내용이 담당해주고 있습니다. 또한 이미지를 업로드할 때 일일히 이미지에 대한 설명을 사용자에게 요구하는 것도 무리입니다. 따라서 img 태그의 alt 속성으로는 간략하게 "img" 라고 적어주겠습니다.

드윗 삭제 과정 분리

사용자가 드윗 삭제 버튼을 누르면 실행되는 콜백 함수입니다. 작동 과정은 이렇습니다.

  1. 사용자에게 브라우저 확인창으로 확인받기

  2. 드윗 문서 Firestore에서 삭제하기

  3. 드윗에 첨부된 이미지 Storage에서 삭제하기

작동 과정 자체는 문제가 없습니다만, 문제는 이미지가 첨부된 드윗과 그렇지 않은 드윗의 삭제 과정을 분리하지 않았다는 것입니다. 그래서 이미지가 없는 드윗을 삭제하면 3번에서 오류 메시지가 출력되었습니다(사용자는 모릅니다.).

조건문을 활용해 이미지 첨부 여부에 따라 3번 과정을 선택적으로 적용하겠습니다.

이렇게 하면 첨부 이미지가 있는 드윗에 대해서만 이미지 삭제가 이루어질 것입니다. 사실 지금 생각해보면 당연한 처리 과정입니다만 오류메시지 덕분에 지금이라도 수정할 수 있어 다행입니다.

snapshot 리스너 메모리 누수 방지

구글의 파이어베이스에서는 데이터베이스 컬랙션에 대해 onSnapshot() 이라는 메서드를 제공합니다. 일종의 데이터베이스 변경 리스너로, 한 번 호출하면 이후 데이터베이스에 쓰기나 삭제 등 변경 사항이 생겼을 때 자동으로 재호출되어 데이터를 업데이트 해줍니다.

드위터에서 이 리스너를 홈 화면과 프로필 화면에 각각 하나씩 쓰고 있습니다. 이 리스너들은 컴포넌트가 랜더를 마쳤을 때 useEffect 후크를 통해 사이드 이펙트로 호출됩니다. 그런데 다른 페이지로 이동했을 때 리스너를 제거해주지 않아 백그라운드에서 계속 리스너가 동작하고 있었고, 이 때문에 콘솔에 메모리 누수 경고가 뜨게 된 것 같습니다.

onSnapshot() 리스너의 연결을 끊을 방법을 찾기 위해 파이어베이스 공식 문서를 찾아본 결과 생각보다 간단한 방법이 있었습니다.

var unsubscribe = db.collection("cities")
    .onSnapshot(() => {
      // Respond to data
      // ...
    });

// Later ...

// Stop listening to changes
unsubscribe();

파이어베이스에서 제공하는 예시입니다. onSnapshot 메소드는 리스너의 연결을 끊는 함수를 반환합니다. 따라서 이 함수를 변수에 저장했다가 useEffect 의 콜백 함수를 통해 정리해주면 될 것입니다. useEffect() 후크에 인자로 넘겨주는 콜백 함수가 반환하는 함수는 컴포넌트가 언마운트 될 때 사이드 이펙트를 정리해주는 기능을 담당합니다. 따라서 unsubscribe 를 호출하는 함수를 콜백 함수의 반환 함수로 만들어주면 될 것입니다.

스냅샷 리스너를 호출하는 함수 안에서 다음과 같이 연결을 끊는 함수를 반환값으로 받아 unsubscribe 변수에 저장하고 이 함수를 최종적으로 반환합니다.

useEffect 의 콜백 함수 내부에서 getDwiites 함수를 호출하며 반환되는 함수를 받아놓고, 스냅샷 연결을 해제하는 함수를 실행하는 함수를 리턴해줍니다. 이제 컴포넌트가 화면에서 사라지기 전에 저 함수가 호출되어 불필요한 리스너 연결을 끊어줄 것입니다.

스냅샷 무한 호출 문제

위의 문제를 해결하는 과정에서 useEffect 에 디펜던시 배열을 넘겨주는 것을 깜빡해 스냅샷 리스너가 무한대로 호출되는 문제가 생긴 적이 있습니다. 이 문제를 알게 된 것은 파이어베이스의 오류 메시지 덕분이었습니다. Quota exceeded 라는 오류메시지의 의미를 몰라 검색해보니 무료 사용량 초과라고 합니다.

몇 분도 안 되는 실행 시간 동안 무려 32만 번이나 파이어베이스에서 데이터를 읽어왔습니다. 원인은 간단했습니다. 화면에 표시되는 드윗 메시지들은 배열에 담겨 dwitteArray라는 state 로 관리됩니다. 그리고 DB에서 불러온 드윗 데이터를를 setDwitteArray 를 사용해 업데이트 해주는 함수가 다름아닌 useEffect 내부의 getDwitte 입니다. 결국 무한 호출은 이렇게 일어난 것입니다.

  • 컴포넌트 렌더
  • useEffect를 통해 스냅샷 리스너 호출
  • 스냅샷 리스너가 드윗 state 업데이트
  • 컴포넌트 리렌더링
  • 리스너 호출
  • 드윗 state 업데이트
  • ...

Firebase 무료 계정이었기 때문에 읽기 횟수 제한이 있어 그나마 다행이었습니다. 만약 종량제였다면 끔찍한 일이 벌어졌을 것입니다. 코딩에 신중을 기해야겠습니다.

이번에는 과거에 신경쓰지 않고 넘어간 결과로 생긴 오류들을 해결하고 그 과정을 정리해보았습니다. 이번 오류 수정을 통해 에러메시지의 중요성을 다시 한 번 느낍니다. 빨간 콘솔창을 보는 것은 고통스럽지만 무엇이 문제이고, 왜 문제이고, 심지어 어떻게 해결해야 하는지까지 가르쳐주는 리엑트의 경고메시지는 대단한 것 같습니다. 다음에도 새로운 업데이트 소식으로 포스팅하겠습니다.


<참고 문서>

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

0개의 댓글