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

앱바 리팩토링 및 네비게이션 개선 #85

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

ohamin26
Copy link
Member

@ohamin26 ohamin26 commented Jan 29, 2025

#️⃣연관된 이슈

#75
#84

📝작업 내용
이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

  • 앱바 리팩토링 및 네비게이션 개선

스크린샷 (선택)

기존 : 무조건 이전 페이지로 이동하는 방식

const ArrowLeft = () => {
  const navigate = useNavigate();
  const onClick = () => {
     navigate('/')
  };

  return (
    <Button onClick={onClick}>
      <img src={CaretLeftIcon} alt="arrow-left" />
    </Button>
  );
};

변경 : 디폴트 ( 이전 페이지) / 사용자 지정 시 해당 페이지로 이동 / 이전 페이지 없을 시 뒤로가기 방지 추가

const ArrowLeft = ({ locate = -1 }: { locate?: string | number }) => {
  const navigate = useNavigate();
  const onClick = () => {
    history.length <= 2 ? navigate('/', { replace: true }) : navigate(locate as string);
  };

  return (
    <Button onClick={onClick}>
      <img src={CaretLeftIcon} alt="arrow-left" />
    </Button>
  );
};

사용방법

<AppBar leftContent={<AppBar.ArrowLeft locate={"/"}/>}  />
<AppBar leftContent={<AppBar.ArrowLeft />}/>

검색페이지 앱바 디자인 변경

width : 100%로 변경

검색 페이지만 별도로 앱바를 만드는 건 관리도 힘들어지고 코드도 복잡해질 거 같아 처음 정했던 방식으로 바꿨습니다
navbar와 같은 width로 맞춰져 있어 보기에도 괜찮은 거 같아요!
image

@jk1635
Copy link
Member

jk1635 commented Jan 31, 2025

기존의 코드는 navigate(-1) 한 가지 방식으로만 뒤로가기가 동작해서, 리다이렉트 이후 뒤로가기 시 예상과 다른 동작이 생겼었어요. 그래서 들었던 생각인데, 각 페이지에서 뒤로가기 동작을 개별적으로 설정할 수 있도록 하는 건 어떨까요? 그러면 페이지별로 원하는 동작을 조금 더 유연하게 사용할 수 있지 않을까 했어요.

제안 예시

const ArrowLeft = ({ onBack }: { onBack?: () => void }) => {
  const navigate = useNavigate();

  const handleBack = () => {
    if (onBack) {
      onBack();
    } else {
      navigate(-1);
    }
  };

  return (
    <Button onClick={handleBack}>
      <img src={CaretLeftIcon} alt="arrow-left" />
    </Button>
  );
};
  • onBack이 없으면, 일반적인 뒤로가기 동작인 navigate(-1)을 실행
<AppBar leftContent={<ArrowLeft />} />
  • onBack이 있으면 커스텀 가능
<AppBar leftContent={<ArrowLeft onBack={() => navigate('/')} />} />
  • 특정 조건에서는 뒤로가기 방지
<AppBar leftContent={
  <ArrowLeft onBack={() => {
    if (window.confirm("정말 나가시겠습니까?")) {
      navigate(-1);
    }
  }} />
} />

추가

물론 변경하신 locate를 사용하는 방법도 조건에 따라 이동할 수 있다는 점에 있어서 위 제안과 유사한 방식이라고 생각해요. 다만, history.length를 사용할 경우에는 실제로 예상과 다르게 동작할 수도 있어요.

아래처럼 handleStatepushState()를 실행해 history.length를 조작한 후, 뒤로가기 버튼(handleHistory)을 누르면 정상적인 동작을 하지 않는 것을 볼 수 있어요.

Screen.Recording.2025-01-31.at.10.38.59.PM.mov
useEffect(() => {
  console.log('초기 히스토리 길이:', history.length);
}, []);

// 1. history 조작
const handleState = () => {
  console.log('조작 전 히스토리 길이:', history.length);
  history.pushState({}, '', location.pathname);
  console.log('조작 후 히스토리 길이:', history.length);
};

// 2. history 이동 테스트
const handleHistory = () => {
  console.log('2. history 이동 실행');
  history.length <= 2 ? navigate('/', { replace: true }) : navigate(locate as string);
};

// 3. navigate(-1)
const handleBack = () => {
  console.log('3. navigate(-1) 실행');
  navigate(-1);
};

결론

  • history.length 기반의 뒤로가기는 예상과 다르게 동작할 수 있다고 생각해요.
  • 그래서 조금 더 안정성을 고려한 navigate(-1) onBack() 등을 사용해서 뒤로가기를 제어해보는건 어떨까요?

@ohamin26
Copy link
Member Author

ohamin26 commented Jan 31, 2025

  • 아래처럼 handleState에 pushState()를 실행해 history.length를 조작한 후, 뒤로가기 버튼(handleHistory)을 누르면 정상적인 동작을 하지 않는 것을 볼 수 있어요.

이렇게 동작하는 걸 의도하고 만들었습니다
history.pushstate()는 history 스택에 값을 추가하는 함수인데, 이 함수가 사용되는 경우는 페이지 이동할 때 말고는 없다고 생각해요

history.pushState({}, '', location.pathname);

예시로 보여주신 이 방식은 강제로 빈 값을 스택에 채워 넣는 건데 사용자 입장에서 이렇게 사용할 경우는 없다고 생각합니다.
만약 사용했다고 해도 그건 사용자가 강제로 값을 추가하는 경우이기에 개발자 입장에서 고려해줄 필요가 없다고 생각해요.
보여주신 예시는 너무 극단적인 예시인 거 같습니다.
결과적으로 보여 주신 예시와 제가 작성한 방식은 차이점이 없다고 생각합니다.
onBack으로 함수를 받는 방식과 locate로 이동할 페이지를 받는 방식이 무슨 차이점이 있는지 잘 모르겠습니다
onBack을 사용할 경우 함수를 하나 더 추가 하는 건데 이 경우 더 비효율적으로 작동할거라 생각해요
그리고 history.length를 사용한 이유는 페이지 이탈을 막기 위해서 추가한거라 안정성 측면에서 봤을 때도 이 방법이 더 안정성이 있다 생각합니다.
그리고 예시로 보여주신건 pushState 후 navigate(-1)을 사용한건데 navigate(-1)의 경우 history 스택에서 pop을 해 이전 페이지로 이동하는 방식이에요. 올려주신 영상대로 작동하는게 정상적인 작동입니다
onBack 함수를 사용하더라도 -1 옵션을 사용할 경우 똑같이 동작할 거 같아요

@jk1635
Copy link
Member

jk1635 commented Feb 1, 2025

예시로 보여주신 이 방식은 강제로 빈 값을 스택에 채워 넣는 건데 사용자 입장에서 이렇게 사용할 경우는 없다고 생각합니다.

저도 사용자가 직접 스택을 추가하는 일은 없다는 부분은 동의해요. 다만, 이외에도 웹뷰(WebView), 데스크탑 웹, 모바일 웹 그리고 각 벤더사의 브라우저 별로 length 값이 모든 환경에서 동일하게 동작한다고 보장할 수는 없어요. 브라우저 별 관리 방식 차이로 예상과 다르게 동작할 수 있어요. 즉, history.length가 이런 측면에서 항상 예측할 수 있는 값은 아니라는 점에서 안정성을 언급했어요.

또, locate 방식은 특정 경로로 이동하는 역할을 하지만, 이동 전에 추가적인 처리를 할 수 없어요. 하지만, onBack 방식은 함수를 받을 수 있기 때문에 이동 전에 window.confirm()을 띄워 사용자의 확인을 받거나, 특정 이벤트 발생 시 추가적 로직 작성이나 상태를 업데이트하는 등의 전처리가 가능해요. 예를 들어, 프로필 페이지에서 수정 중 뒤로 가기를 했을 때, 저장되지 않은 정보가 사라질 수 있다고 경고할 수 있어요. 단순한 이동만 필요한 경우 locate 방식이 적절하지만, 유연성과 확장성을 고려하면, 함수 방식이 다양한 시나리오를 지원할 수 있어서 제안드렸어요.

그리고 백버튼의 기본 동작이 navigate(-1)인건 좋다고 생각해요. 이 방식이 브라우저의 동작을 재현하기 때문에, 여러 환경에서도 동일한 뒤로가기 동작을 할 수 있어요. 실제로 react-router-domnavigate(-1)은 내부적으로도 window.history.go(-1)(history.back())과 같은 방식으로 동작하더라고요. 제가 위에 작성한 navigate(-1) 예시는 history.length값의 변화와 상관없이 navigate(-1) 바르게 동작함을 보여드리려 한 건데, 다시 보니 실험이 잘못되었네요. 이 부분은 혼란을 드렸다면 사과드립니다.

추가로 하민님이 말씀한 안정성인 '페이지 이탈을 막는 것'도 중요한 부분이라고 생각해요. 이전 페이지가 없을 때 다른 사이트로 가는 것보다 저희 서비스의 홈으로 보내는건 정말 좋은 방식이라고 생각해요. 다만 이걸 좀 더 다양한 환경에서도 일관성있게 적용할 방법이 있을지 얘기해보면 좋을 것 같아요.

아래는 참고삼아 네이버 뉴스, 마켓컬리, 당근 채용 사이트의 뒤로가기를 확인한 영상이에요. 첫 번째랑 두 번째는 페이지를 이탈하는 경우이고 세 번째는 이탈하지 않고 특정 페이지로 보내주더라고요.

하민님이 고민하고 작성하신 코드가 세 번째 케이스가 맞나요?

Screen.Recording.2025-02-01.at.8.08.53.PM.mov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In review
Development

Successfully merging this pull request may close these issues.

[Refactor] 앱바 디자인 개선 [Refactor] AppBar 뒤로가기 버튼 로직 점검
2 participants