Kimsora✨
article thumbnail
Published 2023. 11. 26. 23:49
React-router v6 React
320x100
반응형

전에는 너무 얕게만 라우터를 본거같아서 이번에는 좀더 세세하게 다루어 보고자한다

 

createBrowserRouter

loadersactionsfetchers등을 사용할 수 있다

  • 동적 체이지에 적합
  • 검색엔진 최적화
  • github-pages 배포가 까다로움

RouterProveder

어떤 Router 객체이든 Router 객체 RouterProvider에 등록되야한다 

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    loader: rootLoader,
    children: [
      {
        path: "team",
        element: <Team />,
        loader: teamLoader,
      },
    ],
  },
]);

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

Outlet

컴포넌트의 children과 같은 개념으로 중첩이 가능해졌고 더 직관적으로 사용하기 위하여 나왔다

하위 경로 요소를 렌더링하려면 상위 경로 요소에서  사용해야한다

const router = createBrowserRouter([
  {
    path: "/",
    element: <RootLayout />,
    children: [
      { path: "/", element: <Home /> },
      { path: "/products", element: <Products /> },
    ],
  },
]);
///
const RootLayout = () => {
  return (
    <div>
      <MainNav />
      <Outlet></Outlet>
    </div>
  );
};

 

errorElement(v5에는 없고, v6에는 있음)

컴포넌트 에러가 발생해서 충돌하거나 컴포넌트의 위치를 찾지 못할 때 사용하며 다른 컴포넌트들에서 발생하는 문제로부터 보호해준다,

이상한 주소로 이동했을 경우에도 사용

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: <Error />,
    children: [
      { path: "/", element: <Home /> },
      { path: "/product", element: <Product /> },
    ],
  },
]);

 

NavLink

 URL이 'to' 에 지정된 URL과 일치할 시, 특정 스타일을 적용할 수 있고, Route의 path 처럼 동작하기 때문에 end 키워드가 있다

style 이나 className 을 지정할때는 콜백함수의 인자로 { isActive } 속성을 전달받으면 된다

<NavLink
              to="/products"
							end
              className={({ isActive }) =>
                isActive ? classes.active : undefined
              }
            >

여기서 end는 끝에만 일치하도록 논리를 변경한다=> 기본적으로 부분적으로 일치하는 경우에도 해당 경로가 일치로 간주 되기 때문이다

index

특정 경로에 대한 기본 컴포넌트를 나타낸다 해당 경로에 진입 할 때 특별한 하위 경로 없이 엔더링할 컴포넌트를 지정하는 역할이다

    	{
        path : '/' ,
        element : <DefaultLayout /> ,
        children : [
        	{ index:true , element : <Home /> },
        	{ path:'sub' , element : <Sub /> },
        ]
        }

만약 접속하면 DefaultLayout 기준으로 들어가게되는데 children의 path 에도 '/' 을 넣게 된다면 경로가 http://localhost:3000// 으로 선언이 되어버리는 현상이 나타난다 그렇기 때문에 path 를 넣는것이 아닌 / 으로 접속을 했을 때 이 레이아웃 밑에 이 페이지를 보여달라는 식으로 index : true 를 적어주면 루트 경로로 이동을 했을 때 문제없이 렌더링이 된다

loder

서버에 요청하지 않고 데이터를 가능한 빨리 가져오기 위해 제공하고 있다

로더는 컴포넌트가 렌더링되기 전에 호출되며 로더 함수가 값을 리턴하면 useLoaderData()로 컴포넌트에서 데이터를 받아 사용할 수 있다

children: [
      { index: true, element: <Home /> },
      {
        path: "events",
        element: <EventRoot />,
        children: [
          {
            index: true,
            element: <Event />,
            loader: async () => {
              const response = await fetch("http://localhost:8080/events");
              if (!response.ok) {
              } else {
                const resData = await response.json();
                return resData;
              }
            },
          },

//
import { useLoaderData } from "react-router-dom";

import EventsList from "../components/EventsList";

const Event = () => {
  const { events } = useLoaderData();

  return <EventsList events={events} />;
};

export default Event;

 

useRouteError

loader에서  throw new Response로 발생시킨 에러데이터를 받을수 있다

function ErrorBoundary() {
  const error = useRouteError();
  console.error(error);
  return <div>{error.message}</div>;
}

*json utility

수작업으로 Reponse를 생성하는건 너무 귀찮아서 나온 helper utility이다

파싱도 안해도 돼서 간편하다

new Response(JSON.stringify(someValue), {
  headers: {
    "Content-Type": "application/json; utf-8",
  },
});

import { json } from "react-router-dom";

const loader = async () => {
  const data = getSomeData();
  return json(data);
};

useRouteLoaderData

현재 렌더링된 경로 데이터를 트리의 어느 곳에서나 사용할수 있다

createBrowserRouter([
  {
    path: "/",
    loader: () => fetchUser(),
    element: <Root />,
    id: "root", // 라우트에 ID를 정의
    children: [
      {
        path: "jobs/:jobId",
        loader: loadJob,
        element: <JobListing />,
      },
    ],
  },
]);

//

function SomeComp() {
  // "root" 라우트의 데이터를 가져와서 사용
  const user = useRouteLoaderData("root");
  // ...
}

자동 생성된 라우트 ID로 데이터를 저장하지만, 이 훅을 더 쉽게 사용하려면 자체적으로 라우트 ID를 제공하게 된다

Action

url을 변경하지 않고 데이터를 서버로 전송할 때 사용된다 주로 Form 컴포넌트와 함께 사용한다


function EventForm({ method, event }) {
  const data = request.formData(); // Form으로 받은 입력값들에 접근하기 위한 방법이다.

  function cancelHandler() {
    navigate("..");
  }

  return (
    <Form method={method} className={classes.form}>
      {data && data.error && (
        <ul>
          {Object.values(data.error).map((err) => (
            <li key={err}>{err}</li>
          ))}
        </ul>
      )}
      <p>
        <label htmlFor="title">Title</label>
        <input
          id="title"
          type="text"
          name="title"
          required
          defaultValue={event ? event.title : ""}
        />
      </p>
  
    </Form>
  );
}

export default EventForm;
export async function action({ request, params }) {
  const data = await request.formData();
  const method = request.method;

  const eventData = {
    title: data.get("title"),
    image: data.get("image"),
    date: data.get("date"),
    description: data.get("description"),
  };
  let url = "http://localhost:8080/events";
  if (method === "PATCH") {
    const someId = params.someId;
    url = `${url}/${someId}`;
  }
  const reponse = await fetch(url, {
    method: method,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(eventData),
  });
  if (reponse.status === "422") {
    return reponse;
  }
  if (!reponse.ok) {
    throw json({ message: "Could not save event" }, { status: 500 });
  }
  return redirect("/events");
}

폼 양식 컴포넌트에서 모든 input요소에 name속성이 있어야 한다 => 나중에 데이터 추출할때 그것을 보고 추출한다

formData메소드를 통해 접근해야하며  get메소드를 통해 제출된 다양한 입력 필드에 접근할 수 있게된다

 

useSubmit

양식 내에서 값이 변경될 때 마나 양식을 제출할 수 있다, 제출할 첫 번째 인수는 다양한 값을 허용,두 번째 인수는 (대부분) 양식 제출 속성에 직접 매핑되는 옵션 세트

  export async function action({ request, params }) {
  const someId = params.someId;

  const response = await fetch(`http://localhost:8080/events/${someId}`, {
    method: request.method,
  });
  if (!response.ok) {
    throw json(
      { message: "Could not fetch details for delete event" },
      { status: 500 }
    );
  }
  return redirect("/events");
}
 
 
 
  const submit = useSubmit();
  function startDeleteHandler() {
    const proceed = window.confirm("Are you sure?");
    if (proceed) {
      submit(null, { method: "delete" });// null을 해줘야 하는데 이는 현재 여기선 데이터가 필요하진 않기 때문
    }
728x90
반응형
profile

Kimsora✨

@sorarar

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그

WH