CreateBrowserRouter와 횡단 관심사 2 - Nav bar

myung hun kang·2023년 4월 19일
0

지난 번에 작성한 내용에 이어서 추가적으로 리펙토링을 진행했다.

유저가 접근한 라우트에 따라서 nav bar에 보여지는 버튼을 다르게 구현하기!

이 부분은 해당 프로젝트를 진행할 당시에 요구사항은 아니었지만 개인적으로 구현을 했었던 부분이었다.

Home 페이지를 제외한 다른 페이지 라우트로 접근하면 해당 라우트로 이동하는 버튼을 제거하는 간단한 구현 내용이다.

하지만 약간의 반복이 들어가는 코드라 개선이 가능하다고 판단했다.

실제로 라우트가 많아져 nav bar에 들어갈 버튼이 많아지면 같은 코들을 반복하게 될 것이다.

이번 글은 간략하게 위 내용을 리펙토링한 후기를 작성하려한다.

동일한 프로젝트 내에서 1편에서 만든 routerData를 가지고 리펙토링을 진행해서 이름을 2 라고 했지만 
CreateBrowserRouter와는 크게 관련있는 내용은 없다.

기존 코드

기존 Navigation 컴포넌트에서 구현한 내용은 다음과 같다.


import { Link, useLocation } from "react-router-dom";
import styled from "styled-components";

const Navigation = ({ children }: { children: React.ReactNode }) => {
  const { pathname } = useLocation();

  return (
    <>
      <NavigationContainer>
        <div className="nav-header">
          <h1>머리글</h1>
        </div>
        <NavigationLink>
          <Link to="/">Home 으로</Link>
          {pathname !== "/todo" && <Link to="/todo">Todo 바로가기</Link>}
          {pathname !== "/signin" && <Link to="/signin">Login 바로가기</Link>}
          {pathname !== "/signup" && (
            <Link to="/signup">회원가입 바로가기</Link>
          )}
        </NavigationLink>
      </NavigationContainer>
      {children}
    </>
  );
};

보시다시피

현재 pathname을 가져오기 위해서 useLocation를 사용했다. 그리고 다른 라우트로 이동하는 Link 들이 나열되어있다.

작동에는 문제가 없지만 계속 pathname !== "/todo" 블라블라 를 반복하고 있다.

DRY - Don't Repeat Yourself

클린코드를 위한 원칙 중 하나이다.
위 언급한 부분이 이 원칙에 위배된다고 생각된다.

일전에 route에 관한 관심사 분리를 위해 만들어둔 router.tsx의 내용을 가지고 개선하도록 하겠다!!


개선 후

우선 전에 작성한 router.tsx 의 코드 일부분이 필요하다.


export const routerData: RouterBase[] = [
  {
    id: 0,
    path: "/",
    label: "Home",
    element: <Home />,
    withAuth: false,
  },
  {
    id: 1,
    path: "/signin",
    label: "로그인",
    element: <SignIn />,
    withAuth: false,
  },
  {
    id: 2,
    path: "/signup",
    label: "회원가입",
    element: <SignUp />,
    withAuth: false,
  },
  {
    id: 3,
    path: "/todo",
    label: "Todo",
    element: <Todo />,
    withAuth: true,
  },
];

이 routerData의 path와 label을 가지고 Navigation의 Link 태그들을 다룰 것이다.

routerData를 export한 후 Navigation 컴포넌트에 import한다.

그리고

routerData를 map메서드를 이용해서 label, path, id 값으로 Link 태그 부분을 만들어 return하도록 구현했다.

// 다른 import 생략
import { routerData } from "router";

interface NavigationProps {
  children: React.ReactNode;
}

const Navigation: React.FC<NavigationProps> = ({ children }) => {
  const { currentPath } = useRouter();

  return (
    <>
      <div>
          {routerData.map(({ label, path, id }) => {
            if (path === "/") {
              return (
                <Link to={path} key={id}>
                  {label} 으로
                </Link>
              );
            }
            return (
              currentPath !== path && (
                <Link to={path} key={id}>
                  {label} 바로가기
                </Link>
              )
            );
          })}
      </div>
      {children}
    </>
  );
};

중요 로직만 가져왔다.
위 useRouter()는 currentPath를 가져오기위한 custom hook이다.

currentPath는 window.location.pathname 으로 현재 라우트의 pathname을 가르킨다.

currentPath와 path가 다르면 해당 라우트로 바로가기 Link를 만들도록 구현했다.

Home의 경우만 어떤 라우트라도 접근이 가능해야하기 때문에 따로 뺐다.

이로써

nav bar에 새로운 Link를 추가하거나 삭제할 때 Navigation 컴포넌트를 건드리지 않고 routerData 만을 수정하여 조정할 수 있게 되었다.


결론

현 프로젝트는 더 이상 route를 나눌 일이 없기 때문에 오버코딩이라고 볼 수도 있지만
난 학습을 위해서니 좋은 연습이 되었다고 생각한다.

이렇게 route에 관한 관심사 분리는 현 프로젝트로는 어느정도 마무리가 된 것 같다.

다음에는 에러 핸들링을 분리하는 연습을 하고 이 시리즈로 돌아오도록 하겠다.

끝.

profile
프론트엔드 개발자입니다.

0개의 댓글