원티드 Todo list 사전 과제 요구사항에 이런 조건이 있었다.
개별 Todo를 조회 순서에 따라 페이지 뒤로가기를 통하여 조회할 수 있도록 해주세요.
Todo 각각의 상세창을 열 때 id를 url 파라미터로 지정해야 할 것 같은데, 한 페이지에서 뒤로가기로 이동할 수 있게 하라는 말이 잘 이해가 되지 않았다..
뒤로가기라는 말에 꽂혀서 엄청 검색을 하다가 history를 알게 되었다. react-router-dom
이 버전 업그레이드 되기 전에 사용되었던 것 같은데,, 뭔가 의심쩍었지만 빨리 끝내고 싶은 마음에 일단 해봤다.
useEffect(() => {
const back = () => {
history.listen(({ action }) => {
if (action === "POP" && show) {
setShow(false);
}
});
};
back();
}, [history, show]);
todo를 클릭했을 때 navigate로 url을 이동시키고, history로 뒤로가기 이벤트를 감지해서 상세창이 열려있을 경우 닫힐 수 있게 했다.
근데 요즘 아무도 안쓰는 개념인 것 같아서 만들고 나서도 찝찝했다. 제이쿼리 쓰는 기분?? 그래서 다른분들 코드를 보고 힌트를 얻어보기로 했다.
(+수정)
알고보니 history API
는 DOM window 객체의 history 객체를 이용할 수 있게 하는 api였고, 바닐라 자바스크립트로 라우팅을 구현할 때 사용할 수 있는 api였다.
DOM의 Window 객체는 history 객체를 통해 브라우저의 세션 기록에 접근할 수 있는 방법을 제공합니다. history는 사용자를 자신의 방문 기록 앞과 뒤로 보내고 기록 스택의 콘텐츠도 조작할 수 있는, 유용한 메서드와 속성을 가집니다.
MDN
유저의 방문 기록을 history 객체에 저장하는데, 만약 뒤로가기를 하면 저장된 기록에서 이전 페이지를 찾아서 로드되도록 하게 된다. 내가 작성한 코드처럼 뒤로가기와 같은 특정 이벤트를 listen 하는 기능도 있다.
과제 제출 페이지에 가보니 useSearchParams
과 같은 react-route-dom 관련 훅이 많이 언급이 되고 있었다.
useSearchParams
는 useState
와 모양새부터 매우 비슷하고 단지 상태 관리하는 게 params라는 것만 달랐다. 멘토님이 url을 상태로 관리할 수 있다는 게 이 뜻이었구나..를 알 수 있었다.
const [searchParams, setSearchParams] = useSearchParams();
// 상세창 열기 -> searchParams에 id값을 세팅
// 상세창 닫기 -> searchParams 비우기
const handleTodoDetail = () => {
if (show) {
setShow(false);
setSearchParams({});
return;
}
setShow(true);
setSearchParams({
...searchParams,
id,
});
};
// params에 id가 들어왔을 경우 해당 상세창 열기
// id가 사라지면 (뒤로가기 했을 때) 창 닫기
useEffect(() => {
if (searchParams.get("id") === id) {
setShow(true);
} else {
setShow(false);
}
}, [id, searchParams]);
url을 상태로 관리하니 뒤로가기 버튼을 눌렀을 때 url이 변경되면서 상세창이 잘 닫힌다. 굳이 뒤로가기 이벤트를 감지할 필요가 없었던..
잘 모르는 훅들을 공부해보려고 react-router-dom 공식문서 사이트에 들어갔다.
Nested routes를 실습해보는 순간 이거구나 했다... 역시 공식문서가 답이었구나.. 정말 웃기게도 그렇게 이해가 되지 않았던 요구사항이 실습을 하자마자 바로 이해가 되었다.
// App.tsx
<Routes>
<Route path="/" element={<Home />}>
<Route path="/:id" element={<TodoDetail />} />
</Route>
</Routes>
Nested routes로 묶어주면 같은 페이지에서 여러 컴포넌트를 보여줄 수 있다. Home.tsx
에서 TodoDetail
이 들어갈 자리에 Outlet
을 넣어주면 params에 id가 들어왔을 때 해당 todo 상세창이 뿅 나타난다.
// Home.tsx
<Container>
<Wrapper>
<TodoForm />
<TodoList />
</Wrapper>
<Outlet />
</Container>
그리고 useSearchParams
는 검색 파라미터로 많이 쓰인다고 한다. 현재 진행중인 리팩토링이 끝나서 컴포넌트를 분리할 수 있게 되면 이 방법으로 수정해 봐야겠다.(‾◡◝)