TC - 18번일지 (리팩토링 4 - loader)

Debug-Life ·2023년 3월 21일
0

지난 시간 복습

백드롭, cancel 버튼 리팩토링
: 기존의 Click 이벤트 핸들러 대신 라우팅을 연결해서 리팩토링함.
백드롭은 useNavigate 훅을 이용해서 상대경로 지정해서.
cancel 은 버튼 속성을 Link 로 변경해서 이것도 상대경로인 시작 페이지로 설정함.


1. loader(), action () 기능

"react-router-dom" 6.4 이상 버전으로 설치했다면
매우 편리한 기능들을 사용 할 수 있다. loader(), action () 기능이다. 설명하기에 앞서서, 기존의 데이터를 가져오는 방식먼저 다시 정리해보겠다.

데이터를 가져올 때 나의 기존 코드와 같이 useEffect를 사용해도 된다.

useEffect를 사용해서 데이터 가져왔던 방식:

1. main.jsx에서 Posts 컴포넌트에서는 렌더링
2. Posts 컴포넌트에서는 PostList 컴포넌트 렌더링 하게 리팩토링 함.
3. PostList 컴포넌트에서 데이터를 가져오는 코드가 있음.

  • useEffect 를 사용해 콜백함수로 async await 를 이용해 fetch() 함수를 통해서 말이다.
  • get(가져오고), post(데이터 보내고) 전부 다 PostList 컴포넌트에서 처리했음.

그런데 이 복잡한 과정(데이터는 보내고 가져오고 하는)을 loader(), action () 기능을 통해서 편리하게 수정 할 수 있다.


1-1. loader () 적용방법

답 : 라우트 정의에 'loader'라는 프로퍼티 추가하면 됨.

✍ main.jsx (에러 있는 상태)

//생략 생략 생략

const router = createBrowserRouter([
  {
    path: "/",
    element: <RootLayout />,
    children: [
      {
        path: "/",
        element: <Posts />,
        loader :() =>{}			// 아직 값으로 받을 함수 정의안해서 에러.
        children: [{ path: "/create-post", element: <NewPost /> }],
      },
    ],
  },
]);

//생략 생략생략

1-2. loader 특징

  1. 함수를 값으로 받는다.
  2. 리액트 라우터는 해당 라우트가 활성화될 때마다 loader에 있는 함수를 실행한다. 즉, 이 요소가 렌더링되려고 할 때마다 loader에 있는 함수가 실행됨.
    여기 있는 함수를 사용해 이 라우트 컴포넌트 또는 이 라우트의 일부로 사용되는 컴포넌트에 필요한 데이터를 미리 로드해 둘 수 있다.
  3. 값으로 사용될 함수엔 비동기 함수도 넣을 수 있다.

1-3. loader 의 값(함수)에 적용 할 내용

  1. HTTP 요청을 전송해 데이터를 가져오는 로직을 추가
  2. 다만 라우터를 정의하는 부분인 main.jsx가 무거워 지므로 이쪽에서 함수를 짜지 않고, 해당 라우트 컴포넌트 파일에서 함수를 작성한다. 나는 Posts 컴포넌트부터 시작함.
  3. PostList 컴포넌트에서 데이터를 가져오는 부분 잘라내서 Posts 컴포넌트에 copy.
  • 그리고 이제 상태 업데이트 코드는 신경쓰지 않아도 된다. 왜냐하면 loader함수는 컴포넌트 바깥에서 실행되기 때문에 컴포넌트 상태를 바꿀 수 없기 때문이다. 이렇게 해도 컴포넌트로 포스트를 가져올 수 있다.
  1. 이 함수에서 화면에 표시할 데이터를 return 하면 그 데이터를 현재 라우트에 렌더링된 요소가 받는다. 즉, loader 특성이 정의된 컴포넌트 요소가 받는것임.

여기까지 한다음에 Posts 컴포넌트에서 loader() 에 값에 들어갈 함수를 작성한다. 데이터를 가져온것을 확인한 다음 그 데이터를 돌려주기 위해 비동기로 작성했다.

✍ Posts.jsx

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

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

export default Posts;

export async function loader() {
  const response = await fetch("http://localhost:8080/posts");
  const resData = await response.json();
  return resData.Posts;
}



1-4. loader 전달받기

  • 여기서 조금 헷갈리는데, Posts 컴포넌트에서 loader 값에 들어갈 함수를 export 했으면 실제로 라우터가 정의되고 Loader 함수를 사용할 곳인 main.jsx에서 이 값을 import로 받아야한다.

  • 그리고 main.jsx에서만 사용할 loader의 이름을 설정해준다.
    (왜냐하면 이름 충돌을 피하기 위해서 :
    : >>> Posts 컴포넌트에서 정의한 Loader 함수는 어디서든 재사용성이 가능하기 떄문에 이름이 겹치는 에러를 방지하기 위해서.)

여기까지 하고서 적용하자. Posts 라우터 정의 부분에 loader를 추가했다.

✍ main.jsx

import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createBrowserRouter } from "react-router-dom";

import Posts, { loader as postLoader } 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 />,
        loader: postLoader,
        children: [{ path: "/create-post", element: <NewPost /> }],
      },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

  • 저장하고 실행하면 리액트 라우터는 이 함수를 실행해 프로미스 값을 받을 때까지 기다렸다가 해당 요소를 렌더링할거다. (이 코드에서는 Posts 컴포넌트다)

  • 그리고 이 loader()에서 반환한 데이터는 이 위에 있는 요소에서 사용할 수 있다. 그러니까Posts 컴포넌트에서 loader 함수를 export 하고 있는데 이 컴포넌트에서 반환하는 데이터를 사용할 수 있다는 말이다. 그리고 중첩된 요소(PostList)도 동일하다.

  • 정리하자면
    리액트 라우터는 loader()에서 반환한 데이터에 이 라우트 요소 또는 중첩된 컴포넌트가 접근할 수 있게 해준다. PostsList에서도 접근할 수 있다.

  • 다만 중첩된 컴포넌트인 PostList에서 접근하려면 한가지 작업을 추가해줘야한다.
    userLoaderData라는 훅을 임포트 해야한다.

    이 훅을 사용할 수 있는 곳은 컴포넌트 함수 내부고, 다른 훅처럼 이 훅도 컴포넌트 함수 안에서만 사용해야 한다.
    이 훅을 사용하면 Posts 라우트에 할당된 loader()에서 반환한 데이터를 얻을 수 있다. 좀 복잡하긴한데 그냥 외우면 된다.
    PostList에서 userLoaderData' 훅을 추가하면 Posts` 컴포넌트에 추가하고 Loader로 반환한 데이터에 접근할 수 있다.

그러니까 Posts.jsx 에서 export로 명시한 export async function loader() 함수에서 리턴한 값에 접근 가능하다는 말임. 왜냐하면 <PostList />Posts.jsx 에 중첩된 컴포넌트이니까.



✍ PostList.jsx



결국 로더함수를 이용하면 그럼 리액트 라우터는 이 함수를 실행해 프로미스 값을 받을 때까지 기다렸다가 이 요소를 렌더링할것임. 그리고 PostList에선 더이상 state와 useEffect가 필요없음. loader 속성으로 데이터를 받았으니 그걸 쓰면 됨.
userLoaderData 훅을 추가해서.



2. action ()적용방법

action에 대해선 다음 포스팅에 정리.



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

0개의 댓글