React로 간단한 SPA Router 구현하기

Yejung·2022년 10월 7일
1
post-thumbnail
post-custom-banner

원티드 프리온보딩 챌린지 과제로 React로 간단한 SPA router 구현하기를 받았다.

github 코드

아래는 RouterRoute 컴포넌트를 직접 구현하면서 했던 고민들이다.

1. Router와 Route는 어떤 기능을 맡을 것인가?

Router는 children으로 들어오는 Route들 중 현재 URI와 같은 path를 가지고 있는 Route의 컴포넌트를 return 받아 출력해주어야한다.

Route는 props로 받아오는 컴포넌트를 return 해주어야 한다.

그래서 Router에서 children으로 들어오는 배열을 조건에 따라 filter 해주었다. 조건은 현재의 window.location.pathnameRoute의 props로 들어가 있는 path가 일치하는지를 체크해주는 것이다.

지금 글을 작성하면서 생각해보니 filter를 사용하는 것보다 배열을 순회하다가 일치하면 바로 return 하고 배열을 더이상 순회하지 않는 것이 children 배열이 커졌을 때 더 효율적일 거 같다는 생각이 든다

2. url은 변경되는데 어떻게 감지할 것인가?

뒤로가기 기능을 구현해야하므로 push로 페이지 이동을 할 때 history.pushState()를 사용해주었다. url 변경은 되지만 페이지가 바뀌지 않았다. url이 변경되면 그것을 감지해서 그에 해당하는 Route를 렌더링 하는 과정이 필요했다.

popstate 이벤트를 window가 감지하도록 하니 뒤로가기, 앞으로 가기만 감지되었다.

https://developer.mozilla.org/ko/docs/Web/API/Window/popstate_event 을 참고하면

history.pushState()와 history.replaceState() popstate 이벤트를 발생시키지 않는다.

고 한다.

따라서 useRouter에서 구현한 push 함수를 사용할 때 pushState로 URI를 변경시켜주고 popstate 이벤트를 생성해 dispatchEvent를 통해 생성한 이벤트를 발생시켜주었다.


결론

뒤로 가기, 앞으로 가기, useRouter의 push 함수를 사용할 때 popstate 이벤트가 발생한다.
Router 컴포넌트에서 이 이벤트를 감지하면 현재 URI와 path를 비교해 알맞는 Route 컴포넌트를 return 한다.


++) 추가 (22.10.09)

멘토님이 수업시간에 해주신 전반적인 피드백을 듣고 코드를 조금 수정했다.

우선 중요한 useEffect 사용!!

내 코드 중

window.addEventListener("popstate", updatePath);

이렇게 이벤트 리스너를 사용하는 부분이 있다.

이 부분은 window, 즉 함수 외부인 DOM에 접근하므로 side effect를 일으킨다. 따라서 useEffect 내부에 작성해주어야 한다.

📍 수정한 코드

useEffect(() => {
  const updatePath = () => {
    setCurrentPath(window.location.pathname);
  };

  window.addEventListener("popstate", updatePath);

  return () => {
    window.removeEventListener("popstate", updatePath);
  };
}, []);

useEffect 내부로 이벤트 리스너를 옮겨주고 unmount시 해지될 수 있도록 cleanup 함수까지 작성해주었다.

또 children.filter()를 사용하면서 배열 전체를 순회하는 것이 비효율적일수도 있겠다고 생각해서 다른 분들 과제 코드를 훑어보았고,

  1. filter 대신 find로 작성해 path를 찾게 되면 더 이상 배열을 순회하지 않게 하는 방법

  2. contextAPI를 사용하여 Route 내부에서 path를 검사해 null 또는 component를 return 하는 방법

이렇게 두 가지 정도의 방법이 있다는 것을 파악했고 첫번째 방법으로 리팩토링 해주었다.

profile
이것저것... 차곡차곡...
post-custom-banner

0개의 댓글