## Browser Router
- react-router-dom에서 `Routes`와 `Route` 를 통해 경로를 지정할 수 있다.
```jsx
import { BrowserRouter, Route, Routes } from "react-router-dom";
import About from "./screens/About";
import Home from "./screens/Home";
import Header from "./components/Header";
function Router() {
return (
<BrowserRouter>
<Header />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
```
## Create Browser Router
- **Browser Router**보다 좀 더 선언적(?)으로 바꿔준다.
- 기존의 방식은 `App()`에서 Router들을 **Render**하였지만 **Create Browser Router는 Router**를 Array 형식으로 표현한다.
- Array 안에는 각각의 요소가 **Path, Element, Children** 값을 가진다.
- **Path** : 경로
- **Element** : 해당 경로에 일치하면 불러올 Components
- **Children** : Path의 하위 페이지 자식들
```jsx
import { createBrowserRouter } from "react-router-dom";
import About from "./screens/About";
import Home from "./screens/Home";
import Root from "./Root";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "",
element: <Home />,
},
{
path: "about",
element: <About />,
},
],
},
]);
export default router;
```
- Children의 요소들은 Parent에서 불러오기 때문에 해당 Children을 띄울 위치를 지정해주어야 한다.
- **Outlet**를 통해 Children Component를 띄울 위치를 지정해주면 된다. 이를 통해 공통 **Components(Header, SideBar, Footer)**를 쉽게 공유할 수 있다.
```jsx
import { Outlet } from "react-router-dom";
import Header from "./components/Header";
function Root() {
return (
<div>
<Header />
<Outlet />
</div>
);
}
export default Root;
```
💡 `App()`에서는 RouterProvider를 통해 사용할 Create Browser Router를 지정해주어야 한다.
> ```jsx
> import { RouterProvider } from 'react-router-dom';
>
> function App() {
> return (
> <Container>
> <RouterProvider router={router} />
> </Container>
> );
> }
> ```
## Error Element
- **ErrorElement**를 통해 Page에서 일어나는 각종 **Errors**를 **Handle** 할 수 있다.
- 각 요소의 **errorElement** 추가해 해당 Page에서 오류가 발생 시 Render 할 Component를 지정할 수 있다.
- **Errors**를 **Handle**하게 되면 특정 Page에서 오류가 발생하게 되더라도 다른 Page는 동작한다.
```jsx
import NotFound from "./screens/NotFound";
import ErrorComponent from "./screens/ErrorComponent";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "",
element: <Home />,
errorElement: <ErrorComponent />,
},
{
path: "about",
element: <About />,
},
],
errorElement: <NotFound />,
},
]);
```
## UseParams - (Create Browser Router)
- Create Browser Router에서 Parameter를 넘겨주기 위해서는 **Path**안에 해당 값을 `:` 으로 명시해주어야 한다.
```jsx
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "",
element: <Home />,
errorElement: <ErrorComponent />,
},
{
path: "about",
element: <About />,
},
{
path: "users/:userId",
element: <Users />,
},
],
errorElement: <NotFound />,
},
]);
```
💡 해당 경로를 통해 얻은 Parameter는 useParam을 통해 값을 받을 수 있다.
> ```tsx
> import { users } from "../../db";
> function Users() {
> const { userId } = useParams();
> return <div>Users {userId} is named : {users[Number(userId) - 1].name}</div>;
> }
> ```
## Outlet
- **Create Browser Router**에서 부모 요소가 자식 요소로 이동할 때는 **절대 경로**가 아닌 **상대 경로**로 이동하면 된다.
```jsx
function Users() {
const { userId } = useParams();
return <div>Users {userId} is named : {users[Number(userId) - 1].name}
<hr />
<Link to="followers">See followers</Link> /* '/'를 빼면 상대경로이다. */
<Outlet />
</div>;
}
```
- 만약 부모 요소에서 자식 요소로 값을 보내고 싶을 때는 **Outlet**에서 **context**를 통해 **해당 값을 넘겨주면 된다.
```jsx
function Users() {
const { userId } = useParams();
return <div>
<h1>
Users {userId} is named : {users[Number(userId) - 1].name}
</h1>
<hr />
<Link to="followers">See followers</Link>
<Outlet context={{
nameOfMyUser: users[Number(userId) - 1].name,
}} /> /* nameOfMyUser 값을 모든 Children에게 넘긴다. */
</div>;
}
```
- **Children**은 해당 값읋 **useOutletContext**를 통해서 전달 받을 수 있다.
- 이때 당연히 TS를 사용하고 있다면 전달 받는 데이터의 **Type**을 지정해주어야 한다.
```tsx
import { useOutletContext } from "react-router-dom";
interface FollowersContextType {
nameOfMyUser: string;
}
function Followers() {
const { nameOfMyUser } = useOutletContext<FollowersContextType>();
return <h1>Here are {nameOfMyUser}'s followers</h1>;
}
export default Followers;
```
## useSearchParams
- **useSearchParams Hook**을 사용해서 Search Parameter를 가져오거나 변경할 수 있다.
- **readSearchParams** : has, get 등 여러 함수를 통해 데이터를 있는지 파악하거나 가져올 수 있다.
- **setReadSearchParams** : Search Parameter를 직접 설정 할 수 있다.
```jsx
function Home() {
const [readSearchParams, setReadSearchParams] = useSearchParams();
setTimeout(() => {
setReadSearchParams({
day: "today",
tomorrow: "123",
});
}, 1000);
console.log(readSearchParams.get("day"));
return <div>
<ul>
{users.map((user) => (
<li key={user.id}>
<Link to={`/users/${user.id}`}>{user.name}</Link>
</li>
))}
</ul>
</div>;
}
```