리엑트 어플리케이션 내에서 다른 페이지로 이동을 해야할 경우 어떻게 해야할까?
예를들어 인스타그램 메인페이지에서 크리스티아노 호날두의 인스타그램으로 들어가기 위해선 'instagram.com'에서 'instagram.com/cristiano'라는 주소로 들어가야한다.
이때 BrowserRouter을 통해서 리엑트 어플리케이션 내에서 위와 같이 페이지 사이에서 이동을 할 수 있다.
이를 위해서는 react-router-dom이라는 패키기가 필요한데 설치방법은 다음과 같다
npm i react-router-dom
이를 위해 Home과 About이라는 단순 텍스트를 반환하는 페이지를 만들어준다.
function Home(){
return <h1>Home</h1>
}
export default Home;
function About(){
return <h1>About</h1>
}
export default About;
해당 텍스틀를 페이지 상단에 표기할 것이기 때문에 Header라는 컴포넌트를 만들어주고 react-router-dom의 링크를 사용해 해당 페이지에 연결하는 작업을 해준다.
import {Link} from "react-router-dom";
function Header() {
return <header>
<ul>
<li><Link to={"/"}>Home</Link></li>
<li><Link to={"/about"}>About</Link></li>
</ul>
</header>
}
export default Header;
이제 Router라는 객체를 만들어 react-router-dom의 BrowserRouter 안에 해당 Header을 담아준다.
import {BrowserRouter, Route, Routes} from "react-router-dom";
import Header from "../components/Header";
import Home from "./Home";
import About from "./About";
function Router(){
return <BrowserRouter>
<Header />
<Routes>
<Route path="/" element={<Home/>}></Route>
<Route path="/about" element={<About/>}></Route>
</Routes>
</BrowserRouter>
}
export default Router;
마지막으로 App 파일에서 해당 Router을 불러와서 랜더링해준다.
import React, {useState} from "react";
import Router from "./screens/Router";
function App() {
const [value, setValue] = useState("");
const onChange = (event: React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: {value},
} = event;
setValue(value);
};
const onSubmit = (event:React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log("hello", value);
};
return (
<div>
<Router/>
<form onSubmit={onSubmit}>
<input
value={value}
onChange={onChange}
type="text"
placeholder="username"/>
<button>Log in</button>
</form>
</div>
);
}
export default App;
정상적으로 BrowserRouter가 동작하는 것을 확인할 수 있다.
리엑트에서 라우터들을 랜더하는 다른 방법은 createBrowserRouter을 사용하는 것이다.
해당 방식을 사용하는것의 장점은 라우터들을 하나의 객체로 관리하고, 라우터들을 루트인 '/'의 children으로 보는 방식으로 가독성이 조금은 좋아진다는 것이다.
기존에 존재했던 Router 파일을 다음과 같이 변경을 해준다.
import {createBrowserRouter} from "react-router-dom";
import Home from "./Home";
import About from "./About";
import App from "../App";
const router = createBrowserRouter([{
path: "/",
element: <App/>,
children: [
{
path: "",
element: <Home/>
},
{
path: "about",
element: <About/>
},
],
}])
export default router;
전에 말했던것과 같이 루트인 "/"의 children으로 Home과 About이 관리가 되며, children 객체의 path를 통해 경로, element를 통해 랜더링이 될 객체를 관리한다.
이제 App파일에 들어가서 랜더링을 하는 부분에서 Outlet을 사용해주어야 하는데, 해당 Outlet은 Router에 있는 파일 즉, Home과 About을 랜더링 해줄 것을 리엑트에 알려준다.
import React, {useState} from "react";
import {Outlet} from "react-router-dom";
import Header from "./components/Header";
function App() {
const [value, setValue] = useState("");
const onChange = (event: React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: {value},
} = event;
setValue(value);
};
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log("hello", value);
};
return (
<div>
<Outlet/>
</div>
);
}
export default App;
그러면 BrowserRouter을 사용했던때처럼 정상적으로 작동하는 것을 볼 수 있다.
createBrowserRouter에서 에러 관리하는 것 역시 조금은 편리해졌다.
단순히 에러가 발생했다는 것을 프린트하는 파일을 하나 생성해준다.
function NotFound(){
return <h1>404 not found.</h1>
}
export default NotFound;
그리고 Router 파일에 돌아와서 단순히 이 ErrorComponenet를 추가해주면 에러가 발생했을때 이를 프린트해주는 것을 확인할 수 있다.
import {createBrowserRouter} from "react-router-dom";
import Home from "./Home";
import About from "./About";
import App from "../App";
import NotFound from "./NotFound";
const router = createBrowserRouter([{
path: "/",
element: <App/>,
children: [
{
path: "",
element: <Home/>
},
{
path: "about",
element: <About/>
},
],
errorElement:<NotFound/>,
}])
export default router;