원티드 프리온보딩 챌린지 과제로 React로 간단한 SPA router
구현하기를 받았다.
아래는 Router
와 Route
컴포넌트를 직접 구현하면서 했던 고민들이다.
Router
는 children으로 들어오는 Route
들 중 현재 URI와 같은 path를 가지고 있는 Route
의 컴포넌트를 return 받아 출력해주어야한다.
Route
는 props로 받아오는 컴포넌트를 return 해주어야 한다.
그래서 Router
에서 children으로 들어오는 배열을 조건에 따라 filter 해주었다. 조건은 현재의 window.location.pathname
과 Route
의 props로 들어가 있는 path가 일치하는지를 체크해주는 것이다.
지금 글을 작성하면서 생각해보니 filter를 사용하는 것보다 배열을 순회하다가 일치하면 바로 return 하고 배열을 더이상 순회하지 않는 것이 children 배열이 커졌을 때 더 효율적일 거 같다는 생각이 든다
뒤로가기 기능을 구현해야하므로 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 한다.
멘토님이 수업시간에 해주신 전반적인 피드백을 듣고 코드를 조금 수정했다.
우선 중요한 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()를 사용하면서 배열 전체를 순회하는 것이 비효율적일수도 있겠다고 생각해서 다른 분들 과제 코드를 훑어보았고,
filter 대신 find로 작성해 path를 찾게 되면 더 이상 배열을 순회하지 않게 하는 방법
contextAPI를 사용하여 Route
내부에서 path를 검사해 null 또는 component를 return 하는 방법
이렇게 두 가지 정도의 방법이 있다는 것을 파악했고 첫번째 방법으로 리팩토링 해주었다.