레시피 공유 웹 사이트로, 글을 업로드하고 댓글을 달 수 있는 커뮤니티입니다.
기초 CRUD 기능이 있는 프로젝트를 개발하고 이를 통해 redux, react-query를 공부하려고 합니다.
- git clone
- vs code 실행 후, 프로젝트 열기
- server 폴더에서 npm start 명령어 입력 후 서버 실행
- client 폴더에서 npm start 명령어 입력 후 프론트 실행
- localhost 3000번 포트 접속.
- 게시판
- 글쓰기 및 파일 업로드 (Naver Cloud Storage)
- 글수정하기
- 글삭제
- 글 조회
- 댓글 (react-query)
- 댓글 쓰기
- 댓글 수정
- 댓글 삭제
- 댓글 조회
- 메인 페이지 (무한 스크롤 - IntersectionObserver API)
- 레시피 검색 기능
- 전체 글 최신순, 인기순 정렬 기능
- 북마크
- 원하는 게시물 저장
- 로그인 및 회원가입 (firebase)
- 로그인
- 로그아웃
- 회원가입
- 마이페이지 (user 정보 - redux 사용)
- 프로필 사진, 별명 변경
- 북마크 기능 – non serializable error
- 현재 글이 즐겨찾기가 되었는지 확인을 위해 redux store에 있는 bookmark 배열에서 현재 글의 postId가 있는지 탐색 과정이 필요했습니다. 탐색 시간을 더 줄이기 위해 bookmark 을 Set자료형으로 사용하려고 했고, non-serializable value 에러가 생겼습니다. Set이 직렬화 불가능 타입이었기 때문입니다.
⁉️ 왜 redux에서 직렬화 타입을 사용하도록 권하는 가?
✔️ 직렬화 불가능 타입은 직렬화 및 역직렬화를 거치면 정보가 유실 되는 위험이 있음
✔️ 직렬화 불가능 타입은 변하기 쉬운 데이터이고, 데이터를 update해도 참조 값이 바뀌지 않아서 redux에서 값의 변경을 탐지하지 못하고 재렌더링을 안하는 문제가 생길수도 있음.
✅ 위의 문제로, array 자료형을 쓰기로 결정했고, 프론트에서 array를 set으로 변경 후 has메소드로 즐겨찾기에 추가했던 postId인지 확인하는 로직을 구현했습니다.
- 댓글 기능 – react–query
프론트에서 댓글을 쓰고, 수정, 삭제 등 변경한 후, 새로 고침을 통해 화면에 업데이트된 데이터를 불러왔습니다.
하지만 새로고침으로 인한 깜빡임 문제 때문에 서버의 데이터 상태가 최신이면 자동으로 API요청을해서 프론트 데이터를 업데이트 할 수 없을까 생각했습니다. 이 부분에서 서버 데이터의 상태를 캐싱하는 라이브러리인 react-query 적용했습니다.
- 무한 스크롤 구현 방식 선택.
1️⃣ scroll event 등록
- document에 스크롤 이벤트를 등록하고 특정 지점을 관찰하면서 스크롤이 해당 엘리먼트 위치에 도달하였을 때 콜백 함수를 등록하는 것.
- 사용자가 스크롤할 때마다 특정 요소가 화면에 보이는지 안보이는지를 계산
- scroll 이벤트를 처리하는 EventTarget.addEventListener()와 element의 위치를 알아내는 Element.getBoundingClientRect()를 이용
💥 단점
✔️ scroll 이벤트는 스크롤이 될 때마다 일어나기 때문에 event handler에 등록된 함수가 단시간에 무수하게 호출,
✔️ getBoundingClientReact() 함수는 특정 지점 위치 계산하는데, viewport와 element의 상대적인 위치 정보를 반환하기 때문에 스크롤이 될 때마다 새로 계산하고 reflow 현상 발생.
- 근본적인 문제: 특정 요소가 보이는지를 판단하는 코드를 위해 main thread(브라우저 자바스크립트 엔진의 single thread)를 낭비. 성능이 나빠질수 있음.
2️⃣ Intersection Observer API
✔️ Intersection Observer API는 특정 엘리먼트가 화면에 들어오는지, 나가는지, 얼마만큼 보이는지, 다시 말해 화면과 특정 엘리먼트가 교차 하는 것을 감지.
✔️ 브라우저는 교차를 계산하기 위해 main thread를 이용하지 않는다.
✔️ intersection observer api를 사용한 경우에는 target이 감지된 경우에만 Main thread에서 function Call을 호출. 이는 target을 감지하는 intersection observer observe 역할(즉, 감지 또는 화면 위치 계산 부분 같은거) 은 Main thread에 영향을 주지 않는다는 것으로 성능 향상에 도움이된다.
✔️ IntersectionObserverEntry의 속성을 활용하면 getBoundingClientRect()를 호출한 것과 같은 결과를 알 수 있기 때문에 따로 getBoundingClientRect() 함수를 호출할 필요가 없어 리플로우 현상을 방지함.
✅ 스크롤이 발생할 때마다 addEventListener 콜백함수 호출 및 element 위치 계산으로 인한 성능문제가 없는 방향으로 Intersection Observer API 를 선택했습니다
- react-query란?
- React Application에서 서버의 상태를 불러오고, 캐싱하며 지속적으로 동기화하고 업데이트 하는 작업을 도와주는 라이브러리
- 등장 배경
- react에서는 서버에서 데이터를 가져오고 업데이트하는 명확한 방법을 제공하지 않음. 개발자가 hooks(useEffect로 fetch)를 이용해서 직접 개발하거나 redux같은 라이브러리를 사용.
- 서버 상태(서버에서 받아오는 데이터)의 특징
- client에서 제어하거나 소유하지 않는 원격의 공간에서 관리되고 유지됨
- fetch, update를 위한 API가 필요
- 신경을 쓰지 않으면 오래된 상태로 방치됨
- 서버 상태를 store에서 관리하게 되면 아래와 같은 도전과제
- 데이터가 오래되었는지 어떻게 알 수 있나?
- 여기 저기서 중복된 요청을 하나로 최적화할 수 있을까?
- 메모리 관리 측면
- 최대한 빠른 데이터 업데이트를 어떻게 할 수 있을 것인가?
- 특징
- 옵션을 제공해서 직접 만들지 않고도 react-query를 통해서 짧은 코드로 대체 가능
- isLoading, onSuccess, onError,,등
- 프로젝트 구조가 기존보다 단순해져 애플리케이션을 유지 보수하기 쉽고, 새로운 기능을 쉽게 구축할 수 있다.
- 캐싱을 효율적으로 관리
- 여러번 같은 데이터 요청시, 한번만 처리
- 옵션을 제공해서 직접 만들지 않고도 react-query를 통해서 짧은 코드로 대체 가능
- redux란
- 자바스크립트 애플리케이션에서 상태를 효율적으로 관리할 수 있게 도와주는 도구
- 등장 배경
- 앱의 규모가 커짐에 따라 MVC패턴의 양방향(모델변경시 뷰도 변경, 뷰 변경시 컨트롤러도 변경 등) 데이터 흐름의 단점을 해소하기 위해 생김.
- 규모가 커지면 데이터의 흐름을 이해하기 어려워지고 버그찾기 어려워짐
- 이에 대한 대안으로 Flux 단방향 데이터 흐름 패턴 개발됨
- React + Flux 구조 + Reducer(데이터 변경 시켜줌) ⇒ Redux가 등장.
- 앱의 규모가 커짐에 따라 MVC패턴의 양방향(모델변경시 뷰도 변경, 뷰 변경시 컨트롤러도 변경 등) 데이터 흐름의 단점을 해소하기 위해 생김.
- redux의 3원칙
- Single source of truth
- 모든 상태는 하나의 스토어 안에 하나의 트리 구조로 저장됨. 모든 데이터의 원천은 store.
- State is read-only
- 상태는 읽기 전용이다.
- 데이터의 변경은 reducer만이 한다.
- Changes are made with pure functions
- 순수 함수 는 외부의 상태를 변경하지 않으면서 동일한 인자에 대해 항상 똑같은 값을 리턴하는 함수(외부 상태를 변경하지 않는 함수)
- 순수 reducer에서 특징
- 반드시 이전 상태, action을 매개변수로함
- 이전의 값을 변경시키지 않고 새로운 데이터를 만들어 반환 (불변성)
- 순수 reducer에서 특징
- 순수 함수 는 외부의 상태를 변경하지 않으면서 동일한 인자에 대해 항상 똑같은 값을 리턴하는 함수(외부 상태를 변경하지 않는 함수)
- Single source of truth
- 장점 및 특징
- 상태 값을 컴포넌트에 종속시키지 않고, 상태관리를 바깥에서 할 수 있게 해줌.
- redux dev tool이 있어서 디버깅이 유리
- state가 바뀌면 해당 state를 바라보고 있는 컴포넌트는 모두 리렌더링됨.
- redux의 데이터 흐름은 단방향으로,
view에서Dispatch라는 함수를 통해action(바뀔 데이터)이 운반되고reducer에 정의된 로직에 따라store의 state가 변화하고 그state를 쓰는view가 변함
- 단점
- 초기에 코드작성이 복잡하다 몇 개의 파일(dispatcher, reducer,,)들을 필수로 만들어야하여 코드량이 늘어남.







