[React] 중첩 라우팅 시 정상적으로 렌더링되지 않아 빈 화면이 뜰 때 (+Outlet)
1. 문제점
localhost:3000/users/sign_in 경로로 접속을 시도했을 때,
'로그인 페이지입니다.'라는 문구가 나오지 않고,
빈 화면이 떴다.
2. 기존 코드
//App.js
import logo from './logo.svg';
import './App.css';
import { Desktop, Mobile, Tablet } from './layouts/ResponsiveComponent';
import { RouterProvider } from 'react-router-dom';
import root from './router/root';
function App() {
return (
<>
<Desktop>
<RouterProvider router={root} />
</Desktop>
<Tablet>
<RouterProvider router={root} />
</Tablet>
<Mobile>
<RouterProvider router={root} />
</Mobile>
</>
);
}
export default App;
App.js를 위와 같이 작성해서 root.jsx 설정을 애플리케이션 전체에 적용하게 했다.
// root.jsx
import { lazy, Suspense } from "react";
import { createBrowserRouter } from "react-router-dom";
import user_router from "./user_router";
const Loading = <div>Loading...</div>;
const Main = lazy(() => import("../pages/main/Mainpage"));
const root = createBrowserRouter([
{
path: "/",
element: <Suspense fallback={Loading}><Main/></Suspense>
},
{
path: "/users",
element: <Suspense fallback={Loading}></Suspense>,
children: user_router()
}
]);
export default root;
localhost:3000을 입력하면 Mainpage가 뜨도록,
localhost:3000/users를 입력하면 아무것도 안 뜨도록 위와 같이 설정하였다. (이게 문제였다.)
또한 url이 users/sign_in, users/sign_up 등과 같은 형태를 띨 때는 user_router와 연결되게 하였다.
// user_router.jsx
import { lazy, Suspense } from "react";
const Loading = <div>Loading...</div>;
const Sign_in = lazy(() => import("../pages/users/Sign_in_page"));
const user_router = () => {
return [
{
path: "sign_in",
element: <Suspense fallback={Loading}><Sign_in/></Suspense>
}
];
};
export default user_router;
user_router에서는 Sign_in_page가 부모의 경로 + sign_in이라는 경로로 연결될 수 있게 하였다.
// Sign_in_page.jsx
const Sign_in = () => {
return (
<>
로그인 페이지입니다.
ghdod
</>
)
}
export default Sign_in;
Sign_in_page 코드는 위와 같다.
3. 원인
user_router() 함수가 children 배열을 반환하도록 작성되어 있지만,
이를 포함하는 부모 라우트(path: "/users" 경로에 해당)는 element가 비어있는 fragment로 작성되었기 때문이다.
따라서 localhost:3000/users/sign_in으로 접근하면, 해당 경로에 해당하는 element가 없어서 빈 화면이 나타난 것이다.
4. 해결방법
부모 경로("/users" 경로)에 Outlet을 추가하였다.
react-router-dom의 Outlet 컴포넌트는 부모 라우트가 중첩된 자식 경로를 렌더링하는 역할을 한다.
// root.jsx
import { lazy, Suspense } from "react";
import { createBrowserRouter } from "react-router-dom";
import user_router from "./user_router";
const Loading = <div>Loading...</div>;
const Main = lazy(() => import("../pages/main/Mainpage"));
const root = createBrowserRouter([
{
path: "/",
element: <Suspense fallback={Loading}><Main/></Suspense>
},
{
path: "/users",
element: <Outlet/>,
children: user_router()
}
]);
export default root;
위와 같이 코드를 수정했더니 localhost:3000/users/sign_in을 주소창을 입력했을 때 로그인 페이지가 잘 뜬다!
왜 Outlet이 필요할까?
- 부모 라우트는 자식 라우트를 렌더링할 영역을 제공해야 함
- Outlet 컴포넌트는 부모 라우트의 JSX 내에서 자식 라우트의 내용을 출력하는 역할을 함
- 만약 Outlet이 없다면, 부모 라우트는 자식 라우트를 어디에 렌더링할지 알 수 없기 때문에, 자식 경로가 존재해도 화면에 아무것도 표시되지 않음