새로고침해도 기존 tab 상태 유지하기 (React '키' 값을 이용하여 state 재설정하기)

드엔트론프·2023년 6월 12일
0
post-thumbnail

들어가며

React '키' 값을 이용하여 state 재설정하기

  • 리액트 스터디를 하면서 처음 알았던 부분중에 하나는, map을 돌리는 배열에서 key 값을 주는 게 아닌, 컴포넌트에 key 값을 주어 다른 컴포넌트라는걸 알려주는 방법이였다.

(react 공식문서 중)
key를 사용해 React가 모든 컴포넌트를 구분하도록 할 수 있습니다. 기본적으로 React는 부모 내의 순서(“첫 번째 counter”, “두 번째 counter”)를 사용해 컴포넌트를 구분합니다. 하지만 key를 사용하면 이것이 첫 번째 counter나 두 번째 counter가 아니라 특정 counter(예: Taylor의 counter)임을 React에 알릴 수 있습니다. 이렇게 하면 React는 테일러의 counter가 트리에 어디에 나타나든 알 수 있습니다!

{isPlayerA ? (
  <Counter key="Taylor" person="Taylor" />
) : (
  <Counter key="Sarah" person="Sarah" />
)}

이걸 활용하여 프로젝트에 적용했다 !

탭 상태 유지하기

  • antd로 작성된 tab이 있다. antd는 적응한다면 정말 좋은 css 툴인듯하다. 팀원분이 antd로 작업한 tab을 훑어보며, 어떻게하면 새로고침해도 탭 상태를 유지할 수 있을까 고민했다.

할 일

  • 상세보기로 들어가면 보이는 2개의 탭 (강의소개, 강의목록) 이 있다.
  • 두 번째 탭인 강의 목록 클릭 후 새로고침을 하면 강의목록의 탭이 보이도록 한다.
  • 뒤로가기 혹은 앞으로가기 할 시, 눌렀던 탭으로 이동하도록 한다.

시도한 방법

  1. 기존에 팀원분이 시도했다 말았던 부분이 있었다. 각 탭을 누르면 탭 정보를 localStorage에 저장한다.

    • 강의 소개의 key 값을 1, 강의목록의 key 값을 2로 저장하는 식이다.
    const onChange = (key: string) => {
        localStorage.setItem("tabs", key);
      };
  2. 새로고침 시 처음 useEffect를 통해 localStorage에서 get 해오고, 해당 value에 따라 defaultActiveKey를 변경해준다.

  • defalutActiveKey는 antd 에서 제공하는 value이다.
    const [tabValue, setTabValue] = useRecoilState(detailTabMenu);
    
    return
    {tabValue ? (
            <Tabs
              defaultActiveKey={tabValue}
              items={items}
              onChange={onChange}
            />
          ) : (
            <Tabs
              defaultActiveKey="1"
              items={items}
              onChange={onChange}
            />
          )}
  • 이 방법은 문제가 있었다.
    1. 새로고침해도 바로 반영되지 않는다. → 아마 리액트에서 Tab이 바뀐걸 알아차리지 못한것 같다.
    2. 다른 강의로 갔음에도 이전에 반영한 value때문에 이전 값이 반영되어 보인다.
      a. 상세페이지’A’에서 강의 목록으로 탭을 변경 후, 상세페이지 ‘B’로 가면 강의목록으로 탭이 먼저 보이는 것이다.
      b. 이는 localStorage에 각 상태를 저장하는게 아니라 강의소개, 강의목록 전체를 공유하는 값으로 저장했기 때문이다.

해결

  • useRecoliStateuseState로 변경
    • 굳이 전역상태를 사용할 필요가 없다. 각 상세강의별로 상태를 확인해주면 된다.
    const [tabValue, setTabValue] = useState("");
  • routing 기능을 활용하여 쿼리스트링 값을 준다.
    const onChange = (key: string) => {
        setTabValue(key);
        localStorage.setItem("tabs", key);
        router.push(`/courses/courses-list/${router.query.slug}?tab=#${key}`);
      };
  • ?tab=#{key}를 통해 탭 클릭 쿼리스트링이 변경되도록 수정했다. 이렇게 되면 새로고침해도 해당 쿼리스트링에 대한 주소를 인식해서 원하는 탭으로 그려진다!

  • Tabs에 key값을 전달해준다.
    • 리액트는 화면에 그려질 때 같은 위치로 인식한다. 이를 간단히 해결하기 위해서는 해당 컴포넌트에 key값을 전달해주면 된다.
    {tabValue ? (
            <Tabs
              defaultActiveKey={tabValue}
              items={items}
              onChange={onChange}
              key={tabValue}
            />
          ) : (
            <Tabs
              defaultActiveKey="introduce"
              items={items}
              onChange={onChange}
              key={tabValue}
            />
          )} 
  • useEffect에 router.asPath를 dependency로 넘겨주어 tabValue에 넘겨준다.
    useEffect(() => {
        if (router.asPath.split("?tab=#")) {
          const isTabValue = router.asPath.split("?tab=#")[1];
          setTabValue(isTabValue);
        }
      }, [router.asPath]);
  • asPath가 변경됐을 때, tab=# 이 있을때만 동작한다.

배운점

  • 항상 느끼지만, 코딩을 하기전엔 누구나 할 수 있는것 같은, 아주 단순한 기능도 실제로 해보려하면 어렵다는 것이다.
  • 재미있는건, 번역스터디를 하며 배웠던 state의 key값을 적용해보았다는 것!
    • 모든 내용이 기억나는 건 아니지만, 아 그런게 있었지! 하며 적용했을 때 된다는 것에 기쁨을 느꼈다.

참고

key로 state 재설정하기

profile
왜? 를 깊게 고민하고 해결하는 사람이 되고 싶은 개발자

0개의 댓글