# Router

## createBrowserRouter()

> BrowserRouter를 생성하는 함수로, v6에서 새롭게 추가된 라우팅 설계 방법
>
> 해당 라우팅 설계방식을 사용하면 v6.4에 추가된  [Data APIs](https://reactrouter.com/en/main/routers/picking-a-router#data-apis)를 사용할 수 있다.&#x20;

{% hint style="info" %}
**Data APIs란?**

라우터가 렌더링하는 컴포넌트에 데이터를 전달하는 기능 등, 데이터 불러오기와 관련된 새로운 기능들이 대거 추가 되었다.
{% endhint %}

```tsx
function createBrowserRouter(
  routes: RouteObject[],
  opts?: {
    basename?: string;
    future?: FutureConfig;
    hydrationData?: HydrationState;
    window?: Window;
  }
): RemixRouter;
```

* **routes** → 라우트 객체 배열
* **basename** → 앱의 기본 이름, '/app' 이라고 설정시 '/'는 '/app'을 가리킨다.

```tsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      { index: true, element: <HomePage /> },
      { path: '/dashboard', element: <DashboardPage /> }
    ]
  }
]);

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

### Routes.tsx

> 테스트 환경에서도 라우트 정보가 필요하기 때문에 라우트 객체 배열을 별도의 모듈로 분리해서 관리

#### `routes.tsx`

```typescript
import Layout from './components/Layout';
import HomePage from './pages/HomePage';
import DashboardPage from './pages/DashboardPage';

const routes = [
  {
    path: '/',
    element: <Layout />,
    children: [
      { index: true, element: <HomePage /> },
      { path: '/dashboard', element: <DashboardPage /> }
    ]
  }
];

export default routes;
```

### createRoutesFromElements()

> React Element 배열을 라우트 객체 배열로 변환하는 함수

createBrowserRouter()를 사용할 때 이전에 사용되던 JSX 형태로 라우터를 구성할 수 있다.

```tsx
declare function createRoutesFromElements(
  children: React.ReactNode
): RouteObject[];

interface RouteObject {
  caseSensitive?: boolean;
  children?: RouteObject[];
  element?: React.ReactNode;
  index?: boolean;
  path?: string;
}
```

#### Usage

```tsx
const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path='/' element={<Layout />}>
      <Route index element={<HomePage />} />
      <Route path='/dashbaord' element={<DashboardPage />} />
    </Route>
  )
);
```

## createMemoryRouter()

> Test 환경에서 createBrowserRouter 대신 `createMemoryRouter`를 사용한다.

```typescript
export declare function createMemoryRouter(routes: RouteObject[], opts?: {
    basename?: string;
    future?: FutureConfig;
    hydrationData?: HydrationState;
    initialEntries?: InitialEntry[];
    initialIndex?: number;
}): RemixRouter;
```

* **initialEntries** → 초기 엔트리 목록 설정, 즉 테스트할 페이지의 첫 렌더링 경로 설정
  * 배열인 이유는 브라우저 히스토리 스택과 동일, (뒤록가기, 앞으로가기 테스트를 하기 위함)
* **initialIndex** → 초기 엔트리 목록\[배열] 중 인덱스를 통해 경로를 선택

```tsx
import { createMemoryRouter, RouterProvider } from 'react-router-dom';

import routes from '../routes';

descirbe('App', () => {
  it('render correctly', () => {
    const router = createMemoryRouter(routes);
    render(<RouterProvider router={router} />)
  )
});
```

해당 함수도 재사용성을 높히기 위해 함수로 추출하자.

```tsx
import { createMemoryRouter, RouterProvider } from 'react-router-dom';

import routes from '../routes';

export function withRoutes(initialEntries = '/') {
  const router = createMemoryRouter(routes, {initialEntries: [initialEntries]});
  return <RouterProvider router={router} />;
  )
}

describe('App', () => {
  it('render correctly', () => {
    render(withRoutes());

    expect(screen.getByText(/이다잉/)).toBeInTheDocument();
  });
});
```

### MemoryRouter VS createMemoryRouter()

두 방법 모두 테스트 환경에서 라우팅을 구현하는데 사용된다.

`createMemoryRouter()`는 실제로 사용되는 전체 라우팅 정보를 그대로 가져와서 구현하기 때문에 전체적인 라우팅 상호작용을 테스트할 때 적합할것 같다.

반면 `MemoryRouter`는  라우트를 주입 받는 식으로 사용하기 때문에 커스텀하기 쉽고, 좀 더 유연한 테스트를 작성할 수  있어서 특정 라우팅 시나리오를 테스트할 때 적합할 것 같다.
