원문 : https://dev.to/devmdmamun/create-contextual-modal-navigation-with-react-router-v6-28k2
리액트 라우터를 이용하면 뒤 배경이 살아있지만, URL이 변경되는 모달을 만들 수 있습니다.
리액트 라우터 v6에 대한 자세한 내용은 해당 게시물을 참고하세요.
Main.js
state props으로 location 객체를 전달합니다.
이에 대해 나중에 더 설명하겠습니다.
import { Link, useLocation } from "react-router-dom";
export const Main = () => {
const location = useLocation();
return (
<div>
<h2>Create contextual modal navigation</h2>
{/* <Link /> 요소에는 state 속성이 있습니다. 그것은 개체를 포함합니다. background를 키로 전달하고 location을 값으로 전달합니다. */}
<Link to="/modal" state={{ background: location }}>
Open Modal
</Link>
</div>
);
};
App.css
스타일은 생략. 아래 코드 샌드박스나 원문을 참고하세요
Modal.js
주인공이지만 특별한 건 없습니다.
import { Link } from "react-router-dom";
export const Modal = () => {
return (
<div className="modalDiv">
<div className="modal">
<h3>Modal</h3>
<Link to="/">
<button>Close</button>
</Link>
</div>
</div>
);
};
Index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Router>
<App />
</Router>
);
App.js
열린 모달을 클릭하여 모달을 열 때 ,배경에 빈 페이지가 있는 모달이 아니라,
이전 페이지 상단에 모달을 표시할 것입니다.
따라서 현재 위치 개체를 사용하는 대신 이전 위치 개체를 <Routes />에 전달합니다.
그러면 <Routes />는 우리가 같은 페이지(이전 위치)에 있다고 생각합니다.
즉, 링크를 클릭하여 모달을 열면 url이 https://localhost:3000/modal로 변경되지만
<Routes />는 위치가 변경되지 않은 것으로 간주합니다.
우리는 main.js 파일에서 state props으로 해당 객체를 전달했습니다.
import "./styles.css";
import { Route, Routes, useLocation } from "react-router-dom";
import { Main } from "./Main";
import { Modal } from "./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 />}>
{background && <Route path="modal" element={<Modal />} />}
</Route>
</Routes>
</div>
);
}
export default App;
위 코드에 약간의 트릭이 있습니다.
주 : 원문 코드에 오류가 있어서 이건 해당 코드를 참조해야 합니다.
background 객체가 있는 경우
링크를 클릭하여 모달을 열면 조건부로 두 번째 <Routes /> 컨테이너에 모델이 표시되고
첫 번째 <Routes /> 컨테이너에 의해 배경으로 홈페이지가 표시됩니다.
하지만 모달 페이지를 직접 방문하면 첫 번째 컨테이너에 모달 경로를 추가해도 홈페이지만 보입니다.
Main.js 파일에 <Outlet /> 요소를 추가하기만 하면 /modal 경로에 대한 모달 또는 기타 컴포넌트를 표시할 수 있습니다.
import { Link, Outlet, useLocation } from "react-router-dom";
export const Main = () => {
const location = useLocation();
return (
<div>
<h2>Create contextual modal navigation</h2>
{/* <Link /> 요소에는 state 속성이 있습니다. 그것은 개체를 포함합니다. background를 키로 전달하고 location을 값으로 전달합니다. */}
<Link to="/modal" state={{ background: location }}>
here <Outlet />
</Link>
</div>
);
};
응용
해당 방법을 이용하면, 링크로 접근하면 페이지에 화면을 보여주고, 페이지에서 클릭하면 모달로 보여주는
인스타그램, 핀터레스트와 같은 동작을 구현할 수 있습니다.
같은게 있으면 다음에 나오는게 우선하는 모양입니다.
코드는 여기 : https://stackblitz.com/github/remix-run/react-router/tree/main/examples/modal?file=src%2FApp.tsx
<Routes location={state?.backgroundLocation || location}>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="gallery" element={<Gallery />} />
<Route path="/img/:id" element={<ImageView />} />
<Route path="*" element={<NoMatch />} />
</Route>
</Routes>
{/* Show the modal when a `backgroundLocation` is set */}
{state?.backgroundLocation && (
<Routes>
<Route path="/img/:id" element={<Modal />} />
</Routes>
)}
동작하는 예제는 https://mklikgbza--github--3000.local.webcontainer.io/ 에서 보실 수 있습니다.
'FrontEnd' 카테고리의 다른 글
zustand와 타입스크립트 [공식문서번역] (0) | 2022.06.29 |
---|---|
React-Hook-Forms로 재사용 가능한 폼 만들기 (0) | 2022.06.28 |
리액트 테스트 : 폼(Form) 테스트 (0) | 2022.06.26 |
리액트 테스트 : implementation details을 피하기 (0) | 2022.06.26 |
리액트 테스트 : React Testing Library로 Counter 테스트하기 (0) | 2022.06.26 |