[ProPro] Routing 리팩토링

jiseong·2022년 5월 7일
0

T I Learned

목록 보기
240/291
post-custom-banner

route 메서드의 일부 코드 분리

route 메서드는 현재 브라우저의 url을 이용해서 적절한 Component를 화면에 렌더링해주는 메서드로 현재는 route 메서드 내부에서 다음과 같이 지정해둔 경로들을 반복하며 match되는 컴포넌트를 찾는 과정이 포함되어있다.

this.routes = [
  { path: '/', Component: MainPage, loginRequired: false },
  { path: '/study', Component: MainPage, loginRequired: false },
  { path: '/detail/:postId', Component: DetailPage, loginRequired: false },
  { path: '/bookmark', Component: BookmarkPage, loginRequired: true },
  { path: '/write', Component: CreatPostPage, loginRequired: true },
  { path: '/write/:postId', Component: EditPostPage, loginRequired: true },
  { path: '/profile', Component: ProfilePage, loginRequired: true },
  { path: '/recommend', Component: RecommendPage, loginRequired: true },
  { path: '/NotFound', Component: NotFoundPage, loginRequired: false },
];

그런데 match되는 컴포넌트를 찾는 과정은 route 메서드에서 분리하여 메서드에서는 찾아낸 component를 렌더링해주는 코드만 작성되어 있다면 처음에 의도했던 목적과 좀더 맞지않을까 생각되어서 분리시키게 되었다.

분리시킨 함수명은 matchUrlToRoute로 현재의 url로 route를 찾는 과정을 나타낸다. 이 과정에서 dynamicPath이라면 값을 저장하여 각 페이지에서 사용할 수 있도록 parameters를 저장해준다.(e.g. 상세페이지에서 사용할 postId)

matchUrlToRoute(currentPath) {
  const params = {};

  const matchedRoute = this.routes.find(route => {
    const splitedRoutePath = route.path.split('/').slice(1);
    const firstPathname = splitedRoutePath[0];

    // 만약 배열의 끝이면 true
    if (firstPathname === 'NotFound') return true;

    // routePath의 갯수가 다르면 false
    // ex) ['detail', ':postId'] , ['detail']
    if (splitedRoutePath.length !== currentPath.length) return false;

    // 중첩 routePath 확인하면서 params 저장
    // ex) path1/:dynamicPath, path1/path2
    return splitedRoutePath.every((routePath, idx) => {
      if (/^:/.test(routePath)) {
        const propName = routePath.slice(1);
        params[propName] = decodeURIComponent(currentPath[idx]);
        return true;
      }

      if (routePath === currentPath[idx]) return true;

      return false;
    });
  });
  
  RouterContext.setState({ params });

  return { ...matchedRoute, params };
}

그러면 이제 route 메서드는 매칭된 route를 사용해서 화면에 렌더링해주면 된다.

  route() {
    const currentPath = RouterContext.state.pathname.slice(1).split('/');
    const { path, Component, params } = this.matchUrlToRoute(currentPath);

    new Component({ container: this.target });
  }

만약 여기서 로그인 유무에 따라 화면을 렌더링 할지말지가 필요하다면 체크하는 함수를 따로 빼서 window.history.replaceState를 활용하면 된다.

const next = loginValidation(loginRequired);
if (!next) return this.replace('/');

함수명 변경

현재 라우팅되어야할 페이지가 로그인이 필요한 페이지인 경우 로그인되어있는지 체크하는 함수로 loginValidation 함수명을 사용했었다. 하지만 이 함수는 boolean값을 반환하기 때문에 의미에 좀더 맞게 is라는 prefix를 사용하기로 했다.

const next = isAllowedRoute(loginRequired);
if (!next) return this.replace('/');
post-custom-banner

0개의 댓글