createBrowerRouter 사용법 : React Router에서 BrowserRouter 에러 발생(v6.4 이상)

2

REACT

목록 보기
11/12
post-thumbnail

혹시나 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장의 도움이 됩니다.

문제상황

import { BrowserRouter } from 'react-router-dom'; // 에러 발생

기존의 방식대로 BrowserRouter 사용 후 에러가 발생했다.
공식문서의 BrowserRouter 챕터에서 나온것처럼 적용했지만 찾을 수 없다는 에러가 발생한다.


원인 : 업데이트 후 미지원

공식문서에 의하면 몇개의 API가 지원되지 않는다고한다. 튜토리얼에도 creatBrowserRouter를 이용하는 방식으로 적용되어있었다.
헷갈리게 왜 공식문서의 BrowserRouter 챕터는 남겨둔건가 알 수 없다.



새로운 라우팅 방식

  • BrowserRouter -> RouterProvider
  • createBrowerRouter()
    : RouterProvider의 props로 createBrowserRouter()의 반환값 전달
    -> 경로 설정 2가지 방식
// index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter,RouterProvider } from 'react-router-dom';

const router = createBrowserRouter(/* 여기서 경로 설정 */)

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    {/* 기존 App.js나 BrowserRouter가 있던 자리를 RouterProvider로 대체 */}
    <RouterProvider router={router} />
  </React.StrictMode>
);

의문점 : App.js가 더이상 필요하지 않나?

튜토리얼에 보니 App.js를 사용하지 않고 바로 컴포넌트를 적용했다. 그래서 관행처럼 App.js 써오던 것을 안쓰게 될까하는 생각이 들었다.
스택오버플로우를 보니 App.js(tsx)에서 <RouterProvider router={router} /> 을 적용한 예시를 보았다. 유지는 되겠다.

// index.tsx 
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);


// App.tsx 
// => RouterProvider 설정
import React from 'react';
import {
  createBrowserRouter,
  createRoutesFromElements,
  RouterProvider,
  Route,
} from 'react-router-dom';
import Layout from './components/Layout';
import Login from './pages/Login';
import Todo from './pages/Todo';

const router = createBrowserRouter(/* 아래 참조 */);

function App() {
  return <RouterProvider router={router} />;
}

export default App;



createBrowerRouter에서 경로 설정

createBrowserRouter(routes, option);
// routes에는 배열 형태의 정보
// option 자리엔 생략가능한 객체(basename, window를 key로 가짐)

첫번째 전달인자 값(routes)으로

  • 기존 방식과 비슷한 Route 컴포넌트로 전달
  • 객체 방식으로 전달

2가지 방법 중 객체 방식으로 전달 이 공식문서에는 먼저 나왔지만, 익숙한 방법부터 설명하겠다.


(1) 기존 Route 컴포넌트로 전달

  • createRoutesFromElements() 사용

공식문서 중첩라우팅 부분에서 확인할 수 있다.
기존의 중첩 방식을 createRoutesFromElements()를 매개체(?)로 익숙한 방식으로 사용할 수 있다.

// 👉 기존 방식 비교용
<BrowserRouter>
  <Routes>
      <Route path="/" element={<Layout />}> 
      {/* <Layout />은 하위 컴포넌트의 위치를 표현하는 <Outlet />를 포함 */}
      		<Route index element={<Main />}></Route> 
			{/* index는 부모 컴포넌트의 경로를 그대로 받음 */}
      </Route>
  </Routes>
</BrowserRouter>

주의점!

❌ Routes
⭕ Route

👉 기존 방식 비교용 코드는 Routes 안에 Route들이 중첩되어있다. 아래 방식에는 Route가 최상단에 포함된다.

// 공식문서에 나온 예제
// Configure nested routes with JSX

createBrowserRouter(
  createRoutesFromElements( //<------------------ 함수 한번 거침
    <Route path="/" element={<Root />}>
      <Route path="contact" element={<Contact />} />
      <Route
        path="dashboard"
        element={<Dashboard />}
        loader={({ request }) => 
          fetch("/api/dashboard.json", {
            signal: request.signal,
          })
        }
      />
      <Route element={<AuthLayout />}>
        <Route
          path="login"
          element={<Login />}
          loader={redirectIfUser}
        />
        <Route path="logout" />
      </Route>
    </Route>
  )
);

// 적용 예시
import React from 'react';
import {
  createBrowserRouter,
  createRoutesFromElements,
  RouterProvider,
  Route,
} from 'react-router-dom';
import Layout from './components/Layout';
import Login from './pages/Login';
import Todo from './pages/Todo';

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<Layout />}> // Layout은 Outlet컴포넌트를 포함
      <Route index element={<Login />}></Route>
      <Route path="todo" element={<Todo />}></Route>
    </Route>
  )
);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

(2) 객체 방식으로 전달

  • 배열 안 객체
    : 기본 형태로 {} 에 path, element key 포함
    const router = createBrowserRouter([  //<-------- 배열 안 여러객체 포함
      {
        path: "/",
        element: <div>Hello world!</div>,
      },
    ]);
  • 추가 key
    • children -> 중첩 표현(배열 속 객체)
    • loader -> 컴포넌트가 로딩되기 전에 전달되는 값
    • action
    • errorElement -> loader나 action 함수 실행시 에러가 발생되면 보이는 컴포넌트 지정
      ...
// 공식문서에 나온 예시
// (1) 기존 Route 컴포넌트로 전달에 언급한 공식문서 예시와 동일

createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    children: [
      { // 필수는 path element
        path: "contact",
        element: <Contact />,
      },
      {
        path: "dashboard",
        element: <Dashboard />,
        loader: ({ request }) =>
          fetch("/api/dashboard.json", {
            signal: request.signal,
          }),
      },
      {
        element: <AuthLayout />,
        children: [
          {
            path: "login",
            element: <Login />,
            loader: redirectIfUser,
          },
          {
            path: "logout",
            action: logoutUser,
          },
        ],
      },
    ],
  },
]);


loader

컴포넌트가 로딩되기 전에 전달되는 값 명시

  • 콜백함수를 value로 가짐
    : 반환값은 컴포넌트 내부의 useLoaderData()를 사용하여 적용 가능
    -> useEffect에서 fetch를 받아오는 것과 같은 효과

The route loader is called before the route renders and provides data for the element through useLoaderData.



TIL

  • 최근 사용해본 최신 버전 : v6.3

친절하지 않은 공식문서.
왼쪽 네비게이션바에는 v5와 차이점 밖에 없어서 v6의 방식대로적용했다가 시작부터 당황했다.
공식문서에 지원하지 않는 API 챕터를 지워주지..
오래 걸리더라도 공식문서 처음부터 목록이라도 훓어봐야겠다. 제일 시급한 언어는 영어🥹
useEffect 나 에러처린 관련 된 부분이 편하다고 하는데 아직 사용해보질 않아서 차근차근 배워야겠다.

0개의 댓글