이전 시간까지 했던 것들은 원하는 페이지들을 각각 라우트 별로 분리해서 추가해주었고, 중첩이 되어 렌더링 되어야 할 컴포넌트들은 레이아웃 라우트로 설정해주었다.
결과적으로 여태까지 MainHeader
가 위치한 RootLayout
컴포넌트가 가장 아랫단에 위치한 레이아웃 컴포넌트로 그 위에 Posts
또 그 위에(그러니까 자식으로) NewPost
컴포넌트를 렌더링 하고 있다.
추가로 spa의 특성을 유지하기 위해 백엔드로 보내지 말아야할 것들을 위해 Link 컴포넌트로 사용자 경험을 좋게 유지시켰다.
목표 : 기존의 백드롭 , cancel, submit 버튼 동작하도록 리팩토링
우선 닫는 동작부터 처리하겠다. Modal창에서 Props을 전달 받아서 닫아주는 클릭 이벤트 부분은 삭제.
왜냐하면 Modal 컴포넌트 안에서 직접 Click 이벤트를 처리할 것이기 떄문에. 이 Modal에는 항상 래핑할 페이지가 있다고 가정하고 라우트 안에서 Modal을 래퍼처럼 사용할 예정임.
다시 말해서 모달의 백드롭을 클릭하면 다른 라우트로 이동할 것임.
✍ Modal.jsx (절대경로 '/' 코드)
import { useNavigate } from "react-router-dom";
import classes from "./Modal.module.css";
function Modal(props) {
const navigate = useNavigate();
function closeHandler() {
navigate("/");
}
return (
<>
<div className={classes.backdrop} onClick={closeHandler} />
<dialog open={true} className={classes.modal}>
{props.children}
</dialog>
</>
);
}
export default Modal;
✍ Modal.jsx (상대경로 ..코드)
import { useNavigate } from "react-router-dom";
import classes from "./Modal.module.css";
function Modal(props) {
const navigate = useNavigate();
function closeHandler() {
navigate("..");
}
return (
<>
<div className={classes.backdrop} onClick={closeHandler} />
<dialog open={true} className={classes.modal}>
{props.children}
</dialog>
</>
);
}
export default Modal;
closeHandler
가 실행됐을 때 이동할 경로를 인자로 넘겨준다. 그래서 저장하고 실행하고서 백드롭을 클릭해 보면 다시 시작 페이지로 이동하는데 성공useNavigate
는 터미널에서 경로 이동하게 알려주는 훅이라 생각하자.✍ main.jsx (경로 확인하자)
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import Posts from "./routes/Posts";
import NewPost from "./routes/NewPost";
import RootLayout from "./routes/RootLayout";
import "./index.css";
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{
path: "/",
element: <Posts />,
children: [{ path: "/create-post", element: <NewPost /> }],
},
],
},
]);
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
그러니까 바로 위 main.jsx 코드에서 보면 /create-post
에서 한단계 부모가 Posts
컴포넌트고 그 경로가 "/",
인걸 확인 할 수 있다.
✍ NewPost.jsx (수정 후 코드)
import { useState } from "react";
import { Link } from "react-router-dom";
import Modal from "../components/Modal";
import classes from "./NewPost.module.css";
function NewPost(props) {
const [enteredBody, setEnteredBody] = useState("");
const [enteredAuthor, setEnteredAuthor] = useState("");
function bodyChangeHandler(event) {
setEnteredBody(event.target.value);
}
function authorChangeHandler(event) {
setEnteredAuthor(event.target.value);
}
function submitHandler(event) {
event.preventDefault();
const postData = {
body: enteredBody,
author: enteredAuthor,
};
props.onAddPost(postData);
props.onCancel();
}
return (
<Modal>
<form className={classes.form} onSubmit={submitHandler}>
<p>
<label htmlFor="body">Text</label>
<textarea id="body" required rows={3} onChange={bodyChangeHandler} />
</p>
<p>
<label htmlFor="name">Your name</label>
<input
type="text"
id="name"
required
onChange={authorChangeHandler}
/>
</p>
<p className={classes.actions}>
<Link to=".." type="button">
Cancel
</Link>
<button>Sumbit</button>
</p>
</form>
</Modal>
);
}
export default NewPost;
여기까지 하고 저장하면 cancel 버튼도 라우팅으로 제대로 동작한다.
수정내용
- NewPost 컴포넌트에 위치해 있을 것이고, 여기선 Link를 사용해 처리해보겠다.
- Link 설정 (to 로 경로설정)
- onClick 이벤트 핸들러 필요없어서 삭제