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] feat: 뒤로 가기 버튼 구현 #1040

Merged
merged 7 commits into from
Jan 7, 2025

Conversation

chysis
Copy link
Contributor

@chysis chysis commented Jan 4, 2025


🚀 어떤 기능을 구현했나요 ?

  • 뒤로 가기 버튼 공통 컴포넌트(BackButton)를 구현했습니다.
  • 기존 목표였던 뒤로 가기 버튼을 포함한 레이아웃은 만들지 않았습니다. 현재는 뒤로 가기 버튼이 필요한 페이지에서 직접 버튼을 배치하면 됩니다.

🔥 어떻게 해결했나요 ?

기대했던 뒤로 가기 레이아웃

image

  • BackButtonLayout은 children으로 페이지를 받습니다.
  • BackButton은 children과 flex-start 정렬되어야 합니다. (시작 라인에 위치)
  • BackButton과 children은 화면 중앙에 배치되어야 합니다.

문제점

  • children으로 오는 페이지들은 width가 화면 전체를 기준으로 한 상대 크기로 지정되어 있습니다. 상세 리뷰 페이지의 경우, 반응형으로 구현되어 있어 화면 크기에 따라 70%, 80%, 92% 등으로 크기가 가변적입니다. 다른 페이지들도 모두 다른 width가 설정되어 있습니다.

  • BackButton과 children을 flex-start 정렬하기 위해 필요한 InnerContainer를 children과 같은 width로 설정하면 요구 사항을 만족할 수 있습니다. 이를 위해 width: auto 또는 width: fit-content 등으로 설정하면, children의 상대 크기와 맞물려 순환 참조가 발생하게 됩니다.

    1. children은 부모의 부모인 BackButtonLayoutContainer(화면 전체)를 기준으로 70%, 80% 등을 적용하고 싶고
    2. 부모인 InnerContainer는 1번에서 계산된 children과 같게 두고 싶은 상태
    • 즉, 자식이 조부모(?)를 기준으로 크기 계산을 한 다음에 부모가 자식의 크기를 따라야 하기 때문에 CSS의 width 계산 순서와 맞지 않게 됩니다.
  • CSS는 순환 참조가 발생하는 경우, 부모는 최초의 자식 width로 fit-content가 결정되고, 그 후 자식은 부모의 width를 기준으로 다시 상대 크기를 갖게 됩니다. 따라서 부모는 화면 전체의 80%, 자식은 화면 전체의 80%의 80%로 설정됩니다. (원래 크기보다 줄어드는 문제)

    • 이렇게 되면 InnerContainer가 children보다 커지기 때문에 flex-start를 적용할 경우 아래 그림과 같이 화면 중앙에 정렬되지 않습니다.
      image

시도해본 방법(대안)

  1. InnerContainer의 width를 자식 크기와 같게가 아닌 100%로 지정하면 children의 width는 잘 설정되지만 BackButton이 children의 시작 위치에 배치되지 않습니다. 이 경우 디자인적으로 만족스럽지 않습니다.

  2. BackButtonLayout의 children으로 오는 모든 페이지는 width: 100%로 두고, BackButtonLayout을 반응형으로 구현하는 방법.

  • 부모를 반응형으로 구현하면 하위 페이지들은 일관적인 UI를 가질 수 있겠지만, 현재는 페이지마다 UI가 다르기 때문에 논의가 필요합니다.
  1. getBoundingClientRect을 사용해서 children의 시작 위치를 TypeScript로 계산해서 BackButton에 left 속성으로 설정하는 방법
  • children을 감싼 Wrapper에 ref를 설정하여 레이아웃 위치를 계산해야 하는데요, 이 경우 Wrapper는 children의 width와 같게 설정되어야 정확한 위치를 계산할 수 있습니다. 하지만 위의 문제점과 동일한 이유로 실제 children의 시작 위치와 Wrapper의 시작 위치가 달라지게 되어 원하는 결과를 얻을 수 없었습니다.
    image
  1. (채택) BackButton이 필요한 페이지에서 버튼만 갖다 쓰는 방법
  • 공통 레이아웃을 만들지 않고, 필요한 곳에서 버튼 컴포넌트만 가져다 사용하는 방법입니다.
  • 유연한 스타일링이 가능하고, 위의 문제점 등을 고민할 필요가 없게 됩니다.

재사용성에 관한 제 생각

  • 리뷰 목록/모아보기 페이지의 경우, 이미 ReviewDisplayLayout이 적용되어 있고, 공통으로 사용되는 ReviewDescription을 처리하기 위해 useContext를 사용하는 등 로직이 복잡하게 얽혀있습니다. 기존의 레이아웃을 그대로 사용하고, BackButton만 가져와 쓰는 것이 더 낫다고 생각합니다.
  • 결국 남는 것은 리뷰 상세 페이지인데, 당장은 하나의 페이지를 위해 공통 레이아웃을 만들 필요는 없다고 생각합니다.
  • 만약 추후에 BackButton을 사용하는 모든 페이지가 일관된 UI를 가지는 것으로 합의된다면 위의 2번 방법을 적용해볼 수 있지 않을까 생각합니다.

📝 어떤 부분에 집중해서 리뷰해야 할까요?

  • 위 문제점과 구현 방법에 대한 여러분들의 생각이 궁금합니다. 추가적인 아이디어가 있다면 알려주세요!

📚 참고 자료, 할 말

Copy link
Contributor

@BadaHertz52 BadaHertz52 left a comment

Choose a reason for hiding this comment

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

뒤로 가기 버튼 구현 방법에 대한 의견

이미 만들어 놓은 받은 리뷰 목록/상세 페이지에 적용해야하니 제약이 있네요
뒤로 가기 버튼을 필요한 곳에 부르는 방안에 재사용 측면에서 더 좋을 것 같아요.

추가 아이디어

여기에 아이디어를 하나 더하자면, BackButton을 감싸는 Wrapper 스타일 컴포넌트를 만든다면, 이미 만들어져있는 리뷰 목록/상세 페이지의 최상단 스타일 컴포넌트에서 선언하는 width에 자동으로 맞출 수 있어서 별다른 스타일 조정/추가 없이 뒤로 가기 버튼 컴포넌트만 추가하만 하면 될 것 같아요.

상세 페이지 (1)

@chysis
Copy link
Contributor Author

chysis commented Jan 4, 2025

🔥수정 사항

바다의 코멘트를 참고하여, 뒤로 가기 버튼을 다른 페이지에서 쉽게 불러와 사용할 수 있도록 했습니다.

  • Wrapper로 감싸서 한 라인을 차지하게 하고, flex-start 적용
  • 버튼의 스타일과 별개로 Wrapper의 스타일도 props로 받을 수 있도록 설정

적용 예시

  • 리뷰 목록/모아보기 공통 레이아웃인 ReviewDisplayLayout에 적용
<ReviewInfoDataProvider>
  <S.ReviewDisplayLayoutContainer>
    <BackButton prevPath="." wrapperStyle={{ marginTop: '3rem' }} />  // 이 부분 추가
    <S.Container>
      <ReviewInfoSection isReviewList={isReviewList} />
      <OptionSwitch options={reviewDisplayLayoutOptions} />
    </S.Container>
    <TopButton />
    {children}
  </S.ReviewDisplayLayoutContainer>
</ReviewInfoDataProvider>

image

@@ -0,0 +1,14 @@
import styled from '@emotion/styled';
Copy link
Contributor

Choose a reason for hiding this comment

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

올라온 styles.tsx에 BackButtonWrapper는 없네요 😲

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

@ImxYJL ImxYJL left a comment

Choose a reason for hiding this comment

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

시각 자료 덕분에 상황 이해가 더 쉬웠어요! 어째 다루기 까다로운 CSS는 다 에프이에게 가는 느낌이...
살짝 이해가 덜 간 부분이 '페이지별로 UI가 다르다' 였는데, 통일된 미디어 쿼리를 사용하고 있지만 그 안에서 UI들이 어떻게 움직이냐가 페이지별로 다르다고 이해하면 될까요?

간단한(?) 코멘트 남겼습니다!


interface BackButtonProps {
prevPath: string;
options?: NavigateOptions;
Copy link
Contributor

Choose a reason for hiding this comment

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

navigateOptions라고 명시하면 BackButton을 사용할 때 무엇을 전달해야 하는지 고민하지 않아도 될 것 같아요!
(이걸 보니 제 로그인 버튼 스타일 이름을 확실히 고쳐야겠다는 생각이 드네요ㅋㅋㅋ)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

명시하는 것이 나을 것 같네요!

Comment on lines 23 to 24
<S.BackButtonWrapper $style={wrapperStyle}>
<S.BackButton onClick={handleBackButtonClick} $style={buttonStyle}>
Copy link
Contributor

Choose a reason for hiding this comment

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

지금은 BackButton을 레이아웃과 엮어서 사용하고 있지만, Wrapper 없이 딱 BackButton만 필요할 때도 있을 것 같아요. 둘을 분리하는 것에 대해 어떻게 생각하시나요? (Checkbox와 CheckboxItem처럼) '뒤로가기' 자체가 레이아웃과 엮일 일이 많으니 그냥 묶어둬도 좋을 것 같고... 😶

그리고 버튼 type은 굳이 지정하지 않아도 되는지 궁금해요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

원래는 레이아웃으로 만들려고 했던 만큼, 뒤로 가기 버튼을 사용하게 된다면 거의 레이아웃 용도로 사용하게 될 것 같아요. 만약 BackButton 자체만 필요한 경우가 생긴다면 그때 두 가지를 모두 지원하는 것은 어떨까요?

버튼 type의 경우 기본값이 submit이기 때문에 button으로 지정했습니다! 👍

Copy link
Contributor

@soosoo22 soosoo22 left a comment

Choose a reason for hiding this comment

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

에프이 BackButton 코멘트

일단... 에프이...!! 고생 많았어요👏👏 확실히 PR에 대략적인 그림과 함께 설명을 자세히 적여주셔서 에프이가 어떤 부분에서 고민이 되었고, 해결하고 싶어했는지 알 수 있어서 정말 좋았어요!

(채택) BackButton이 필요한 페이지에서 버튼만 갖다 쓰는 방법

에프이가 시도해 본 여러 방법들 중에 채택된 방법이 가장 좋은 방법 같네요!

getBoundingClientRect을 사용해서 children의 시작 위치를 TypeScript로 계산해서 BackButton에 left 속성으로 설정하는 방법

저도 처음엔 PR보고, getBoundingClientRect로 left 값 가지고 와서 계산하면 되지 않을까?? 하고 생각했어요. BackButton의 시작 위치를 특정 요소의 시작 위치와 동일하게 맞추길 원한다면 Contentsref를 주고, Contents의 자식 컴포넌트인 ReviewDisplayLayoutContainerleft 값을 계산해서 BackButtonleft 값에 반영해요. 경로가 변경될 때마다 useEffect로 감지해서 left 값을 업데이트하는 방식으로?

    <S.MainContainer $isShowBreadCrumb={isShowBreadCrumb}>
      <S.BackButtonLayoutContainer>
        <BackButton prevPath="." wrapperStyle={{ marginTop: '3rem' }} left={currentTabLeft} />
        <S.Contents ref={buttonRef}>{children}</S.Contents>
      </S.BackButtonLayoutContainer>
    </S.MainContainer>
2025-01-06.12.40.43.mov

다만, 이 방법을 사용하면 위 영상처럼 정확한 값을 얻을 때도 있지만, 상황에 따라 값이 정확히 계산되지 않을 때도 있는 것 같네요….😭 값이 정확하지 않아 화면에 다르게 보이는 일이 생기는 것 보다는, 에프이가 채택한 방식이 보다 안전하고 최선의 방법 같네요! 수고했어요:)

Copy link
Contributor

@ImxYJL ImxYJL left a comment

Choose a reason for hiding this comment

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

변경사항 확인했습니다! 다양한 방법 시도하느라 고생 많았어요 👍👍

@chysis
Copy link
Contributor Author

chysis commented Jan 6, 2025

다만, 이 방법을 사용하면 위 영상처럼 정확한 값을 얻을 때도 있지만, 상황에 따라 값이 정확히 계산되지 않을 때도 있는 것 같네요

맞습니다! getBoundingClientRect를 사용했을 때 계산을 제대로 못하는 경우가 있었어요. children을 감싸는 요소의 width 때문에 그런 것 같네요😓 여기에 margin 등 추가적인 스타일링이 들어간다면 안정성이 굉장히 떨어질 것 같아요.

Copy link
Contributor

@BadaHertz52 BadaHertz52 left a comment

Choose a reason for hiding this comment

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

열어보니, 생각해야하는 케이스들이 까다로운 기능 구현하느라 고생했어요 🚀

@BadaHertz52 BadaHertz52 merged commit b033992 into develop Jan 7, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[FE] 뒤로가기 버튼을 포함한 레이아웃 컴포넌트를 구현한다.
4 participants