Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 이벤트 페이지 api 호출 개선 #686

Merged
merged 2 commits into from
Oct 2, 2024
Merged

[FE] 이벤트 페이지 api 호출 개선 #686

merged 2 commits into from
Oct 2, 2024

Conversation

jinhokim98
Copy link
Contributor

issue

구현 근거

아래 영상을 보면 행사 이름 레이아웃이 먼저 보이고 행사 이름이 채워진 후 아래 step 들이 보이게 됩니다.
사용자에게 깜빡거리는 안 좋은 경험을 주게 됩니다.

2024-09-28.12-53-31.mp4

이런 현상을 해결하기 위해선 컴포넌트를 랜더링 하기 전에 필요한 데이터를 전부 불러온 뒤에 컴포넌트를 랜더링하면 되지 않을까 해서 적용해봤습니다.

고민점

  1. react-router loader 도입에 대한 고민
    처음에는 react-router의 loader 기능을 활용해서 컴포넌트가 랜더링 되기 전 데이터를 load 한 뒤 랜더링을 하려고 했습니다.
    우리는 서버 상태를 react-query로 관리하며 react-query와 loader를 같이 사용하기 위해선 router에서 query client가 필요해집니다. 하지만 router는 jsx element를 반환하는 컴포넌트가 아니기때문에 hook을 사용할 수 없습니다.

즉 useQueryClient를 사용해서 queryClient를 받아올 수 없기 때문에 지금 작성된 구조로는 loader를 도입하는데 어려움이 있다고 생각했어요

  1. 컴포넌트를 감싸는 Loader
    그렇다면 react-router의 loder와 비슷하게 구현해보면 되지 않을까 해서 컴포넌트를 감싸는 로더를 만들어봤어요
<EventLoader>
  <EventPageLayout />
</EventLoader>

위 구조와 같이 Loader를 만들어줍니다.
그리고 Loader 안에서 react-query를 사용해서 api 호출을 해줍니다.
이 때 이벤트에 필요한 세 가지 정보, (Event, Report, Step)를 useQueries를 이용해 병렬적으로 불러오도록 변경했습니다.
병렬적으로 불렀을 때의 장점은 한 페이지에 필요한 정보를 한 번에 실행시키기 위함입니다.

 const queries = useQueries({
    queries: [
      {queryKey: [QUERY_KEYS.event], queryFn: () => requestGetEvent({eventId, ...props})},
      {
        queryKey: [QUERY_KEYS.reports],
        queryFn: () => requestGetReports({eventId, ...props}),
      },
      {
        queryKey: [QUERY_KEYS.steps],
        queryFn: () => requestGetSteps({eventId, ...props}),
      },
    ],
  });
const isLoading = queries.some(query => query.isLoading === true);
return !isLoading && children;

그리고 로딩이 아닐 경우에 children을 랜더링하도록 설정해서 데이터가 로딩 중일 때는 컴포넌트가 랜더링되지 않고 로딩이 끝난 후 데이터가 준비가 됐을 때 children이 보이도록 했습니다.

개선 결과

2024-09-28.12-53-43.mp4

더 개선해야 할 점

로더를 통해 데이터를 미리 가져오지만 staleTime이 설정되지 않아 데이터를 불러오자마자 stale 처리되어 하위에서 다시 데이터가 fetch 됩니다. 이 부분은 조금 아쉬워요

🫡 참고사항

@jinhokim98 jinhokim98 added 🖥️ FE Frontend 🚧 refactor refactoring labels Sep 28, 2024
@jinhokim98 jinhokim98 added this to the v2.0.1 milestone Sep 28, 2024
@jinhokim98 jinhokim98 self-assigned this Sep 28, 2024
Copy link

@jinhokim98 jinhokim98 linked an issue Sep 28, 2024 that may be closed by this pull request
1 task
const EventLoader = ({children, ...props}: React.PropsWithChildren<WithErrorHandlingStrategy | null> = {}) => {
const eventId = getEventIdByUrl();

const queries = useQueries({
Copy link
Contributor

@pakxe pakxe Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 useQueries는 처음봅니다. 여러개의 쿼리 콜백을 넘겨주고 한번에 실행하는 훅인가봐요. 새로이 알게되었습니다 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞아요! 세 개의 쿼리를 병렬적으로 한 번에 불러올 수 있는 훅입니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리액트 쿼리 장인 쿠키..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굉장히 좋은 방식이고 접근이지만, 결국 쿼리를 불러오는 역할이 2개씩이 된 것 같아 보이긴 하네요...
그래도 기본적으로 request~를 동일하게 사용하다보니 유지보수가 크게 어려울 것 같다는 생각이 들지 않긴 합니다~!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뭔가 EventLoader보다도 Suspense 역할인 것 같아서 이런 이름을 녹여내도 좋을 것 같아요!

const {updateTotalExpenseAmount} = useTotalExpenseAmountStore();

useEffect(() => {
if (queries[2].isSuccess && queries[2].data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 queries.length - 1로는 기능하지 않나요?.?

개인적으로 조금 궁금한 점이 있는데요. 왜 하필 2번째의 쿼리가 모두 완료되어야 하는건가요? useQueries가 동적병렬쿼리를 위한 훅이라고 검색해보니 나오는데.. 병렬이라면 2번째 쿼리가 완료되어도 그 외 쿼리가 완료되지 않았을 가능성은 없나요? 순서는 보장되는 것일까요?!🥹 혹시 쿠키도 이 훅에 대해 잘 모른다면 넘겨도 좋아요. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

queries.length - 1 이것도 가능하지만 2번째 있는 데이터가 steps이고 steps를 이용해서 totalAmount를 계산하므로 명시적으로 2를 사용했어요!

왜 하필 2번째의 쿼리가 모두 완료되어야 하는 건가요?에 대한 답은
저 useEffect 문은 아래 로딩과는 관계없이 updateTotalAmount를 계산해주기 위함이었어요.
2번째 데이터가 준비됐을 때 총 금액을 계산해라!는 의미였어요

그런데 여기에서도 한 번 더 계산하고 있어서 두 번 계산하지 않도록 지우는 것이 더 좋을 것 같아요!

const AdminPage = () => {
  const {steps} = useRequestGetSteps();
}

Copy link
Contributor

@pakxe pakxe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

문제를 해결하기 위해 여러 방법들을 두고 어떤게 적절할지 실행해보며 고민하는 모습이 참 좋습니다 😆 그런 모습을 보며 저도 의욕을 전해받는 것 같아요.

비포 애프터가 영상으로 첨부되어 있어서 어떤 문제를 해결했는지 빠르게 파악할 수 있었어요. 제일 좋은건 결국 문제를 해결해냈다는 것! 👍👍👍

Copy link

github-actions bot commented Oct 1, 2024

@jinhokim98
Copy link
Contributor Author

문제를 해결하긴 했지만 한 편으로 다른 고민도 있어요.
데이터가 다 준비가 된 뒤 랜더링하는만큼 사용자가 흰 화면을 오래 보게 되는 것도 있어요.

화면이 끊겨 보이는 것 vs 사용자가 흰 화면을 오래 보는 것

두 가지를 보면서 어떤 경험이 더 좋지 않은지 이야기해봐요.
이렇게 이야기하는 이유는 LCP가 아주 처참하기 때문입니다..ㅜㅜㅜㅜㅜ

Copy link
Contributor

@soi-ha soi-ha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

유저를 위해 개선해줘서 고마워요 쿠키!
확실히 저번에도 말했지만 한번에 로딩되긴 전 흰 화면이 뜨는 데, 이걸 어떻게 하는 것이 좋을지 고민이네요..
로딩 화면을 띄울 것인가.. 아님 다른 방법이 있을런지...

제가 생각하기에는 로딩 화면을 띄우는게 현재 상황에서는 가장 좋은 방법이라고 생각해요~

const EventLoader = ({children, ...props}: React.PropsWithChildren<WithErrorHandlingStrategy | null> = {}) => {
const eventId = getEventIdByUrl();

const queries = useQueries({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리액트 쿼리 장인 쿠키..

Copy link
Contributor

@Todari Todari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

갓갓쿠... 슬슬 우리도 최적화나 성능 개선을 힘써야 할 때가 되었네요!! 고마워용

const EventLoader = ({children, ...props}: React.PropsWithChildren<WithErrorHandlingStrategy | null> = {}) => {
const eventId = getEventIdByUrl();

const queries = useQueries({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굉장히 좋은 방식이고 접근이지만, 결국 쿼리를 불러오는 역할이 2개씩이 된 것 같아 보이긴 하네요...
그래도 기본적으로 request~를 동일하게 사용하다보니 유지보수가 크게 어려울 것 같다는 생각이 들지 않긴 합니다~!

const EventLoader = ({children, ...props}: React.PropsWithChildren<WithErrorHandlingStrategy | null> = {}) => {
const eventId = getEventIdByUrl();

const queries = useQueries({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뭔가 EventLoader보다도 Suspense 역할인 것 같아서 이런 이름을 녹여내도 좋을 것 같아요!

@Todari Todari merged commit 5d5d9f1 into fe-dev Oct 2, 2024
2 checks passed
@Todari Todari deleted the feature/#683 branch October 2, 2024 04:58
@Todari Todari mentioned this pull request Oct 2, 2024
Todari pushed a commit that referenced this pull request Oct 2, 2024
* refactor: event loader를 이용해서 이벤트에 필요한 정보 병렬적으로 데이터 불러옴

* refactor: 총 금액 업데이트 계산을 로더에서 제거
@Todari Todari mentioned this pull request Oct 10, 2024
Todari added a commit that referenced this pull request Oct 10, 2024
* fix: 정산 초대하기에 누락된 margin 적용 (#682)

* refactor: 이벤트 페이지 api 호출 개선 (#686)

* refactor: event loader를 이용해서 이벤트에 필요한 정보 병렬적으로 데이터 불러옴

* refactor: 총 금액 업데이트 계산을 로더에서 제거

* feat: 토스 송금 기능 개선 (#688)

* test: prop 변경으로 스토리북 변경

* refactor: 클립보드 복사 후 토스 열기에서 토스 url스킴을 자세히 이용해 송금정보 자동 입력되도록 변경

* fix: 계좌번호 수정되지 않던 버그 해결 (#691)

* feat: staleTime, gcTime 설정 (#607)

* feat: 검색엔진 최적화를 위한 meta 태그 작성 (#696)

* chore: meta 태그 설정

* fix: 잘못 설정된 og:locale 태그 수정

* feat: TopNav 버튼 강조 및 계좌번호 접근 관련 (#697)

* feat: event login 페이지 제거

* feat: auth gate를 통해 관리자인지 체크할 수 있도록 변경

* feat: 관리자가 아니고 계좌번호가 입력되지 않았을 때, 정산자에게 문의를 하라는 토스트

* style: eventOutline -> event로 이름 변경

* refactor: 초대버튼의 역할을 외부로 분리해서 주입해주는 것으로 변경

* feat: 정산 초대 및 송금기능 타겟 환경에 따른 flow 개선 (#701)

* feat: 공유버튼 모바일과 데탑 분리

* feat: 송금버튼 새로운 반영사항 적용

* feat: 계좌번호 없을 때 금액 복사 기능 추가

* test: prop 변경으로 인한 스토리북 변경

* feat: 계좌번호 없을 때 금액 복사되는 onCopy 추가

* feat: 다나까 -> 요 체로 변경

* feat: 송금기능 페이지 이동으로 인해 memberId 추가

* feat: 송금 페이지 라우트

* feat: 송금하기 버튼을 눌렀을 때 navigate state로 정보 전달

* feat: 송금 방법(복사, 카카오페이, 토스) 제공

* feat: 아래 => 토스열기 명시적으로 변경

* feat: Banner 컴포넌트 생성

* feat: 세션스토리지 util 추가

* feat: 계좌번호 입력 유도 기능 구현

* feat: Flex div prop도 받도록 설정

* feat: 돌아가는 Chevron 컴포넌트 생성

* feat: 바깥 클릭 시 실행되는 컴포넌트 생성

* feat: Select 컴포넌트 제작

* feat: 요구사항 변경으로 인한 송금 플로우 변경

* feat: Select 컴포넌트 제작

* design: 텍스트 색깔 변경

* style: export 정리

* feat: 이벤트 별로 배너 상태 다르게 적용되도록 event token 인자 추가

* refactor: admin page 기능들 훅으로 분리

* feat: Footer 구현하기 (#709)

* fix: 토스 형식에 맞지 않는 은행이름 수정 (#713)

* feat: 멤버 추가할 때 버튼을 사용할 수 있도록 함 (#715)

* design: Button 컴포넌트에 Input의 height와 똑같은 크기의 semiLarge 사이즈 추가

* refactor: Flex컴포넌트의 스타일 추가 프롭을 otherStyle -> cssProp으로 이름 수정

* feat: emotion 에서 사용하는 css타입으로 Flex 컴포넌트의 스타일을 주입할 수 있도록 수정

* chore: Flex 컴포넌트의 프롭명이 달라짐에 따른 수정

* design: Input 컴포넌트가 width100%를 차지하도록 함

* feat: 멤버 추가 버튼을 클릭했을 때 멤버를 추가하도록 함수 구현

* feat: 멤버 스텝에 멤버 '추가'버튼을 추가하고 클릭되었을 때 실행할 로직 연결

* chore: props 이름 변경으로 인한 수정

* �fix: react-query 캐싱 적용으로 인해 발생한 버그 해결 (#716)

* fix: onSuccess에 currentMembers queryKey refetching 추가하기

* fix: 행사를 생성할 때 마다, queryKey event refetching 추가하기

* fix: 새로운 행사 생성시 기존(이전 행사)의 query 모두 제거

* fix: toast.error, toast.none이어도 모두 toast.confirm으로 출력되는 문제 (#720)

* chore: 사용하지 않고있는 변수 제거

* fix: 토스트 타입에 따라 다른 아이콘이 뜨도록 타입을 제대로 명시해서 넘겨줌

* feat: 사진 업로드 기능 (#723)

* fix: 기존에 잘못된 url 주소 변경

* feat: carousel 구현

* fix: api 요청 방법 변경

* fix: image post api 수정

* feat: image 불러오기 위한 기능 구현

* fix: 스크롤바가 보이지 않도록 변경

* design: Carousel 디자인 변경

* fix: 사진 추가 버튼 커스텀

* feat: images 불러오는 api 추가

* feat: Carousel component 구현 완료

* feat: 사진 추가 페이지 구현

* feat: 요청으로 불러오는 Images 타입 선언

* feat: 홈에서 이미지를 확인할 수 있는 기능 추가

* fix: 행사 생성 시 다른 query들 초기화하도록 변경

* fix: style이 제대로 적용되지 않던 문제 해결

* style: lint 적용

* fix: mock url 변경

* feat: imageDelete api 추가

* fix: service type 수정

* refactor: AddImagesPage 구조 변경 및 delete api 추가

* fix: 불필요한 z-index 제거₩

* fix: merge 충돌 해결

* feat: 초대하기를 링크 공유와 카카오톡을 선택할 수 있도록 변경 (#719)

* feat: 공유버튼 모바일과 데탑 분리

* feat: 송금버튼 새로운 반영사항 적용

* feat: 계좌번호 없을 때 금액 복사 기능 추가

* test: prop 변경으로 인한 스토리북 변경

* feat: 계좌번호 없을 때 금액 복사되는 onCopy 추가

* feat: 다나까 -> 요 체로 변경

* feat: 송금기능 페이지 이동으로 인해 memberId 추가

* feat: 송금 페이지 라우트

* feat: 송금하기 버튼을 눌렀을 때 navigate state로 정보 전달

* feat: 송금 방법(복사, 카카오페이, 토스) 제공

* feat: 아래 => 토스열기 명시적으로 변경

* feat: Banner 컴포넌트 생성

* feat: 세션스토리지 util 추가

* feat: 계좌번호 입력 유도 기능 구현

* feat: Flex div prop도 받도록 설정

* feat: 돌아가는 Chevron 컴포넌트 생성

* feat: 바깥 클릭 시 실행되는 컴포넌트 생성

* feat: Select 컴포넌트 제작

* feat: 요구사항 변경으로 인한 송금 플로우 변경

* feat: Select 컴포넌트 제작

* design: 텍스트 색깔 변경

* style: export 정리

* refactor: ClickOutsideDetector 사용

* feat: dropdown base 미트볼, 버튼 두 개 지원

* style: dropdown list z-index 추가

* feat: 드랍다운 버튼을 클릭할 때 드랍다운 리스트가 닫히는 기능 구현

* feat: 모바일에서 링크 초대와 카카오톡 초대 분리

* feat: 공유 메시지 변경

* feat: amplitude tracking 코드 작성 (#733)

* feat: amplitude 트래킹 코드 구현

Co-authored-by: JinHo Kim <[email protected]>

* chore: 불필요한 console.log제거

* feat: 이벤트 생성, 시작버튼 클릭, 지출내역 체류시간 track 함수 제작

* feat: track 코드에 진입 브라우저 프로퍼티 추가

* feat: 정산 시작하기 track 코드 추가

* feat: 이벤트 로더에서 총액 계산

* feat: 이벤트 초대 클릭 track 코드 추가

* feat: 지출내역 시작, 종료 tracking 코드 추가

* feat: 송금하기 tracking 코드 추가

* chore: 필요하지 않은 의존성 제거

* style: lint 맞춰줌

* fix: 개발 편의로 인한 sentry 주석 해제

---------

Co-authored-by: 이태훈 <[email protected]>
Co-authored-by: JinHo Kim <[email protected]>

* fix: 사진 추가한 후 다시 접속 시 반영이 되지 않는 버그 (#727)

* fix: post를 기다린 후 navigate시켜서 캐시 데이터가 remove 됨을 보장받도록 변경

* feat: 잘못 설정된 canSubmit, setIsPrevImageDeleted 변경

* feat: body 타입이 FormData인 경우 header를 삽입하지 않도록 함

* feat: images POST 요청을 requestPostWithoutResponse 함수를 이용하도록 함

* fix: get 메소드가 오류날 때, 무한 렌더링이 일어나는 문제 수정

---------

Co-authored-by: 이태훈 <[email protected]>
Co-authored-by: pakxe <[email protected]>

* fix: 송금에서 데스크탑 환경은 복사하기밖에 보이지 않도록 수정 (#735)

* feat: 데탑 기본 값을 복사하기로 변경

* fix: select box 클릭시 목록이 없어졌다가 생기는 오류 수정

* �fix: 이미지 추가 및 조회 기능에서 발생하는 버그 (#737)

* fix: 이미지 추가 페이지에서 발생하던 오류 수정

* design: 사진 추가하기 버튼 색상 변경

* fix: 사진이 없을 때, 홈에서 사진 조회를 할 수 없도록 변경

* fix: eventName에 따라 og태그가 변경되도록 수정 (#739)

* fix: meta tag 수정

* feat: 행사 이름에 따라 meta tag가 변경되도록 수정

* fix: EventPageLayout이 사용되지 않는 경우, 기존 meta 태그가 보이도록 변경

* fix: unmount시 기존의 태그로 변경되도록 적용

* style: lint 적용

---------

Co-authored-by: Soyeon Choe <[email protected]>
Co-authored-by: JinHo Kim <[email protected]>
Co-authored-by: Pakxe <[email protected]>
Co-authored-by: JinHo Kim <[email protected]>
Co-authored-by: pakxe <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🖥️ FE Frontend 🚧 refactor refactoring
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

[FE] 이벤트 페이지 api 호출 개선
4 participants