Introduction
modal을 만드는 것은 쉽다. 왜냐하면 이제는 html에서도 dialog라는 tag를 이용해 간단한 html과 js조합으로 쉽게 만들 수 있기 때문이다. 그러나 우리가 사이트들을 사용하면서 보이는 modal 중에는 html이 아닌 react를 이용해 만든 modal들도 있는데 둘의 차이는 react를 이용하면 url이 변경됨에도 modal 주변으로 이전 페이지가 렌더링되게 할 수 있다는 점이다.
대표적으로는 instragram이나 twitter에서 해당 방법을 사용하는 것을 알 수 있는데 이 방법을 사용했을 때 장점으로는 사용자들이 페이지 전/후 이동이 직관적이라는 점이다. url이 바뀌면서 modal이 보이는 경우 뒤로가기 버튼을 눌렀을 때 modal이 띄워지기 이전 페이지로 돌아간다. 즉, modal 주변 배경이 되고 있는 페이지로 돌아가는 것이다.
그러나 url이동없이 modal를 쓰는 경우 사용자가 뒤로가기 버튼을 누르면 modal의 전전 페이지로 돌아가는 것처럼 보인다. 왜냐하면 사용자들은 modal를 하나의 페이지로 인식하기 때문이다. 따라서 이런 경우 사용자가 modal을 닫기 위해서는 modal의 x버튼을 눌러야만 한다.
따라서 사용자에게 더 좋은 경험을 주기 위해 react-router-dom v6을 이용해 url이 변화했을 때 modal 페이지와 이전 페이지를 동시에 렌더링하는 방법에 대해 알아보고자 한다.
Preliminaries
Popup
팝업은 사용자가 특정 작업을 수행할 때 나타나는 작은 창이다. 이는 주로 광고, 경고, 추가 정보 제공 등을 위해 사용된다. 팝업은 사용자가 현재 작업을 계속할 수 있도록 종종 페이지의 배경에 띄워진다.
Modal
모달은 사용자가 특정 작업을 완료하거나 중요한 정보를 확인할 때까지 기본 콘텐츠와의 상호작용을 차단하는 창이다. 모달은 사용자의 주의를 요구하며, 배경을 흐리게 하거나 차단하여 현재 작업에만 집중하게 한다. 사용자는 모달에 제시된 작업(예: 양식 제출, 확인)을 완료하기 전까지 다른 페이지 요소와 상호작용할 수 없다.
Popup vs Modal
팝업과 모달의 차이점은, 모달은 사용자가 모달 외의 다른 요소와 상호작용하는 것을 차단하지만, 팝업은 그렇지 않다는 것이다. 모달은 사용자의 결정이나 입력을 필요로 하는 중요한 상황에 사용되며, 팝업은 사용자에게 추가 정보를 제공하거나 선택적인 상호작용을 제안하는 데 사용된다. 또한 정보의 양에 있어서도 차이가 있다고 생각하는데 일반적으로 모달은 정보의 양이 많기 때문에 창으로 띄워졌더라도 사용자가 별도의 페이지로 인식한다. 따라서 모달을 구현할 때는 페이지 이동이 있어야 사용자가 웹서핑할때 좋은 경험을 줄 수 있다고 생각한다.
따라서 난 모달과 팝업을 각각 구현할 때 페이지 이동이 있냐 없냐로 구분해서 구현하였다. Figrue1을 보면 창이 띄워져도 url의 변화는 없는 것을 볼 수 있다. Figure2에서는 창이 띄워짐에 따라 url이 변화하지만 이전 페이지가 모달의 배경으로 렌더링된다. 이런 모달을 구현하는 방법은 아래와 같다.
Show me the Code
먼저 modal을 여는 버튼이 있는 main파일을 만든다.
main.js에서 눈여겨 볼 것은 4번째 줄의 uselocation함수와 8번째 줄 link component의 state prop이다. uselocation함수는 현재 위치(url)을 가져오는 hook이고 state prop은 이동할 페이지인 modal로 이 location 변수를 전달한다. 사용자가 main페이지에서 modal페이지로 이동하기 때문에 background인 modal 이전 페이지가 main페이지가 되는 것이다.
import { Link, useLocation } from "react-router-dom";
export const Main = () => {
const location = useLocation();
return (
<div>
<h2>Create contextual modal navigation</h2>
<Link to="/modal" state={{ background: location }}>
Open Modal
</Link>
</div>
);
};
modal파일은 크게 다른 것이 없다. usenavigate hook을 이용해 닫는 버튼을 구현하였고 div로 modal을 직접 구현하였다. dialog tag를 이용해 구현하여도 된다.
import { useNavigate } from "react-router-dom";
export const Modal = () => {
const navigate = useNavigate();
return (
<div className="modalDiv">
<div className="modal">
<h3>Modal</h3>
<button onClick={() => navigate(-1)}>Close</button>
</div>
</div>
);
};
다음으로 index.js이다. 일반적인 index와 조금 다른 점은 router태그를 index파일에서 쓴다는 점이다. 왜냐하면 추후에 app.js에서 uselocation hook을 쓰기 때문인데 router 외부에서 hook을 사용할 수 없기 때문에 router태그를 index.js로 옮겨온 것이다.
마지막으로 중요한 app.js파일이다.
import "./App.css";
import { Route, Routes, useLocation } from "react-router-dom";
import { Main } from "./components/Main";
import { Modal } from "./components/Modal";
function App() {
const location = useLocation();
const background = location.state && location.state.background;
return (
<div className="App">
<Routes location={background || location}>
<Route path="/" element={<Main />}>
<Route path="modal" element={<Modal />} />
</Route>
</Routes>
{background && (
<Routes>
<Route path="modal" element={<Modal />} />
</Routes>
)}
</div>
);
}
export default App;
modal page와 이전 페이지를 모두 렌더링 하고 싶기에 routes의 location prop의 default값인 current location이 아닌 이전 location과 현재 location을 모두 준다. main.js에서 state prop으로 background를 줬기에 background가 있는 상황이면 두번째 routes가 렌더링 된다. 이에 따라 이전 페이지가 배경으로 보이는 것이다.
Reference
https://dev.to/devmdmamun/create-contextual-modal-navigation-with-react-router-v6-28k2
'React' 카테고리의 다른 글
React lifecycle 이해하기 (0) | 2024.07.10 |
---|---|
SPA와 MPA의 차이, 작동 원리에 대해서 (feat CSR, SSR) (0) | 2024.07.04 |
React와 JWT로 자동 로그인 구현하기 (0) | 2023.12.24 |
동적 라우팅을 이용한 게시글 별로 달라지는 URL 구현 (0) | 2023.08.06 |
Useeffect hook의 리턴구문 실행 조건 (0) | 2023.08.06 |