TC - 16번일지 (리팩토링 2)

Debug-Life ·2023년 3월 19일
0

저번 시간에 이어서 리팩토링 시작.

5. 중첩 라우트

목표: Post 목록 위에 NewPost를 오버레이 하기.

해법 : 레이아웃 컴포넌트를 사용해서 NewPost를 Posts 컴포넌트 자식으로 추가하고 y축의 + 방향으로 렌더링한다.

formModal에 래핑 되어서 NewPost 컴포넌트가 렌더링 되기까지 성공했다.
그런데 이미 포스팅된 Post들 위에 렌더링 되지 않는 문제가 생겼다.

그래서 Posts 컴포넌트 (이전의 App 컴포넌트) 자체를 레이아웃 컴포넌트로 바꿔야 한다.왜냐하면 Posts 컴포넌트가 PostList를 렌더링 하기 떄문이다.

✍ Posts.jsx (App.jsx에서 변경한 코드)

import PostList from "../components/PostList";

function Posts() {
  return (
    <>
      <main>
        <PostList />
      </main>
    </>
  );
}

export default Posts;

Posts 컴포넌트에 측면 메뉴 바, 메인메뉴 바 같은 건 없지만, 여전히 요소를 가지고 있고 그건 NewPost 컴포넌트에도 필요하다. (PostList 컴포넌트)
그러니까 RootLayout 에서 children으로 래핑했던 것처럼 레이아웃을 설정해줘야한다.
결국 똑같은 작업임.



✍ 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>
);
  • 수정 작업 : 기존 RootLayout 의 children에 있던 자식 2개의 컴포넌트 객체인 PostsNewPost 가 있었고, 여기서 Posts를 레이아웃 라우트로 만들고 그 자식으로 NewPost 를 추가했다.

  • 결국 이렇게 하면 중첩의 중첩이 된다. 총 3중첩이다. 제일 아래엔 RootLayout 두번쨰엔 Posts 마지막 그 위엔 NewPost 컴포넌트가 위치한다.
    다시말해 NewPost 컴포넌트가 Posts 라우트의 자식 라우트가 된다.

  • 결과는 새 포스트 모달 창을 포스트 목록 위에 표시할 수 있게 된다.
    + 이전 작업과 동일하게 main 섹션 위에 Outlet을 추가해야 한다.

근데 왜 NewPost가 PostList 위에 그려져야함?
<PostList /> 아래에 <Outlet /> 을 추가하면 모달창 + NewPost 컴포넌트가 포스트 목록 아래쪽으로 이동해서 원하는 레이아웃이 나오질 않기때문이다.


✍ Posts.jsx (추가 후 코드)

import { Outlet } from "react-router-dom";
import PostList from "../components/PostList";

function Posts() {
  return (
    <>
      <Outlet />
      <main>
        <PostList />
      </main>
    </>
  );
}

export default Posts;

저장 하고 다시 화면을 보면 NewPost 컴포넌트가 Posts 위에 오버레이되어서 나타난 것을 볼 수 있다.

그런데 여전히 처리해야할 것들이 남아있다.

5-1. 추가로 해야할 것들

  1. url을 일일히 입력하는것이 아니라 이전의 상태처럼 NewPost를 클릭하면 새 창이 열리고 url도 /create-post 로 바뀌게 되어야한다.
  2. NewPost를 닫거나 여는것도 이전 작업과 동일하게 해주어야함.



6. 경로 연결 & 경로 탐색

목표 :
1. 경로 연결
2. NewPost 버튼 클릭으로 NewPost 열고 백드롭 클릭하면 닫도록 리팩토링.

해법 :
1. useNavigate 훅을 써서 라우트의 경로 url 바꿔주기 (라우터에서 제공하는 기능)
2. Link 속성 이용해서 url 경로 바꿔주기 (라우터에서 제공하는 기능)


둘 중에 뭘써야 할까? 우선 나는 Link 방식을 이용한다

그러니까 내가 dpp 라는 어플을 만들었다고 가정했을떄, 프로그래밍 탐색방법은 이 어플내에서 내 어플의 라우터 경로가 아닌 다른 웹페이지의 경로를 로드하는 방식이고
Link를 쓰는 방식은 dpp 즉, 내 어플내에서 경로를 이동하게 해주는 방식이기 때문이다.



1. 경로연결

NewPost 컴포넌트 버튼과 main.jsx/create-post 경로를 연결해줘야한다.

✍ MainHeader.jsx (수정 후 코드)

import { MdPostAdd, MdMessage } from "react-icons/md";
import classes from "./MainHeader.module.css";

function MainHeader() {
  return (
    <header className={classes.header}>
      <h1 className={classes.logo}>
        <MdMessage />
        Twitter Clone App
      </h1>
      <p>
        <a href="/create-post" className={classes.button}>
          <MdPostAdd size={18} />
          새로운 포스트
        </a>
      </p>
    </header>
  );
}
export default MainHeader;
  • 수정 내용 : 버튼 속성 대신 a 속성으로 바꾸고, 안의 속성중에서 onClick 이벤트 핸들러 삭제, MainHeader 컴포넌트에서 onClick 이벤트로 사용되던 매개변수 삭제
  • 이렇게 저장하고 기본 라우트 http://127.0.0.1:5173/ 여기로 들어가서 NewPost 버튼 눌러보면 원하는대로 NewPost가 렌더링된다.

문제 발생

그런데 여기엔 아주 큰 문제가 있다. 이 방식은 데이터를 백엔드에서 새롭게 불러온다. 그러니까 새로고침하는 방식과 같다. 즉, 시간이 오래걸리고 사용자 경험이 매우 좋지 않아진다. 어플의 크기가 커지고 가져와야할 데이터가 많아질 수록 그렇다. 그러면 리액트를 사용하는 의미가 없다.

다시 말해서 동작하긴 하지만 싱글 페이지 애플리케이션에서 이런 식으로 페이지를 다시 로드하면 전역으로 관리하던 상태를 모두 잃게 되고 모든 자바스크립트 코드를 다시 다운로드하고 그 코드를 전부 다시 실행하기 때문에 성능에 매우 좋지 않다.


해결방법

Link 컴포넌트 사용한다. (a 태그 대신에)

서버에 새로운 요청을 보내지 않고도 URL을 변경하고, 새로운 컴포넌트를 로드하면 된다.

특징

1. Link도 내부적으로 앵커 요소를 렌더링하지만 브라우저가 자동으로 요청을 전송하지 못 하게 막아준다.
2. Link는 href 속성이 아니라 'to' 속성으로 경로를 받는다.

✍ MainHeader.jsx (Link 삽입 후 코드)

import { Link } from "react-router-dom";
import { MdPostAdd, MdMessage } from "react-icons/md";
import classes from "./MainHeader.module.css";

function MainHeader() {
  return (
    <header className={classes.header}>
      <h1 className={classes.logo}>
        <MdMessage />
        Twitter Clone App
      </h1>
      <p>
        <Link to="/create-post" className={classes.button}>
          <MdPostAdd size={18} />
          새로운 포스트
        </Link>
      </p>
    </header>
  );
}
export default MainHeader;

저장하고 확인해보면 버튼클릭시 새롭게 새로고침하는 화면이 보이지 않고, 기존 페이지에서 url만 바뀌고 NewPost가 렌더링 되는것을 확인할 수 있다.



profile
인생도 디버깅이 될까요? 그럼요 제가 하고 있는걸요

0개의 댓글