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

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

 

1. createBrowserRouter

loaders actions fetchers 등을 사용할 수 있다

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

2. RouterProveder

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

<bash />
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> );

3. Outlet

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

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

<bash />
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에는 있음)

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

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

<bash />
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 } 속성을 전달받으면 된다

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

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

index

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

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

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

4. loder

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

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

<bash />
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로 발생시킨 에러데이터를 받을수 있다

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

*json utility

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

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

<bash />
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

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

<bash />
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 컴포넌트와 함께 사용한다

<bash />
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

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

<bash />
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