Skip to content

Commit

Permalink
Merge pull request #94 from TakhyunKim/docs/protected-route
Browse files Browse the repository at this point in the history
Protected Route 에 λŒ€ν•œ ν¬μŠ€νŒ… μ—…λ‘œλ“œ πŸŽ‰
  • Loading branch information
TakhyunKim authored Jun 14, 2023
2 parents c10d724 + 50e0ff9 commit 2f7c34d
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 0 deletions.
334 changes: 334 additions & 0 deletions posts/protected-route.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
---
title: "Protected Route 둜 μ•ˆμ „ν•˜κ²Œ 정보, κΈ°λŠ₯ λ³΄ν˜Έν•˜κΈ°"
subtitle: "React μ—μ„œ Protected Route κ΅¬ν˜„"
date: "2023-06-12"
thumbnailUrl: "/images/protectedRoute/thumbnail.jpg"
tag: "react,protected route"
description: "React λ₯Ό μ‚¬μš©ν•΄μ„œ Protected Route κ΅¬ν˜„"
postingType: "post"
---

μ•žμœΌλ‘œ React λ₯Ό 기반으둜 λ‹€μ–‘ν•œ μ‹œλ‚˜λ¦¬μ˜€λ₯Ό λŒ€μ‘ν•˜λŠ” 것을 정리해볼 μƒκ°μž…λ‹ˆλ‹€.<br />
Protected Route λŠ” 첫 번째 μ‹œλ‚˜λ¦¬μ˜€μ΄λ©°, κ΅¬ν˜„ν•΄μ•Όν•  μ‹œλ‚˜λ¦¬μ˜€μ™€ <br />
μ •μ˜ 직접 κ΅¬ν˜„ν•˜λ©΄μ„œ λ¦¬λ§ˆμΈλ“œν•˜κ³  μƒˆλ‘œ λ°°μ› λ˜ λ‚΄μš©μ„ μ •λ¦¬ν•©λ‹ˆλ‹€.

μ‹€μ œ κ΅¬ν˜„μ€ μ•„λž˜ GitHub Repo 링크λ₯Ό 톡해 확인해보싀 수 μžˆμŠ΅λ‹ˆλ‹€.

- [protected route with react GitHub Repo](https://github.com/TakhyunKim/react-study/tree/main/protected-route)

## κ΅¬ν˜„ μ‹œλ‚˜λ¦¬μ˜€

1. νŽ˜μ΄μ§€λŠ” "메인", "둜그인", "λ§ˆμ΄νŽ˜μ΄μ§€", "λŒ€μ‹œλ³΄λ“œ" λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.
2. λ‘œκ·ΈμΈν•œ μœ μ €κ°€ μ•„λ‹Œ 경우, "λ§ˆμ΄νŽ˜μ΄μ§€", "λŒ€μ‹œλ³΄λ“œ" λŠ” μ ‘κ·Όν•  수 μ—†μŠ΅λ‹ˆλ‹€.
3. λ‘œκ·ΈμΈν•œ μœ μ €μΌ 경우, 둜그인 νŽ˜μ΄μ§€λ‘œ μ ‘κ·Ό μ‹œ 메인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.

## μ •μ˜

이름 κ·ΈλŒ€λ‘œ Route λ₯Ό protected ν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.<br />
`νŠΉμ • 쑰건` 을 λ§Œμ‘±ν•˜μ§€ μ•Šμ„ 경우, νŠΉμ • νŽ˜μ΄μ§€λ‘œ μ΄λ™μ‹œν‚€κ³ ,<br />
`νŠΉμ • 쑰건` 을 λ§Œμ‘±ν•  경우, ν•΄λ‹Ή νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.<br />

보톡 인증과 같이 μ μ ˆν•œ κΆŒν•œμ΄ μ—†λŠ” μœ μ €λ‘œλΆ€ν„° 정보, κΈ°λŠ₯을 λ³΄ν˜Έν•˜κΈ° μœ„ν•΄<br />
νŠΉμ • κ²½λ‘œμ— 접근을 방지할 λ•Œ `Protected Route` λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

## λ¦¬λ§ˆμΈλ“œ ν˜Ήμ€ λ°°μ› λ˜ 점

### μ‹œλ‚˜λ¦¬μ˜€ 외적 μ²˜λ¦¬ν•  λΆ€λΆ„ - replace

이번 `Protected Route` λ₯Ό κ΅¬ν˜„ν•˜λ©΄μ„œ 둜그인이 λ˜μ–΄μžˆμ§€ μ•Šμ€ μœ μ €λŠ” login νŽ˜μ΄μ§€λ‘œ route ν•˜λŠ” λ‘œμ§μ„ κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.<br />
이 κ³Όμ •μ—μ„œ `replace` μ˜΅μ…˜μ„ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ„ 경우 μ–΄λ–€ μ΄μŠˆκ°€ λ°œμƒν•˜λŠ”μ§€ μž‘μ„±ν•˜κ² μŠ΅λ‹ˆλ‹€.

> 1. login 을 ν•˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ `Protected Route` 된 `λŒ€μ‹œλ³΄λ“œ`, `λ§ˆμ΄νŽ˜μ΄μ§€` 둜 μ΄λ™ν•©λ‹ˆλ‹€.
> 2. `Protected Route` 둜 인해 login νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.
> 3. login νŽ˜μ΄μ§€μ—μ„œ λ’€λ‘œκ°€κΈ°λ₯Ό ν•©λ‹ˆλ‹€.
μœ μ €λŠ” login νŽ˜μ΄μ§€μ— κ°‡νžˆλŠ” 상황이 λ©λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

`Protected Route` 에 μ˜ν•΄ login νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜λ©΄ λΈŒλΌμš°μ € History Stack 은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.<br />
처음 메인 νŽ˜μ΄μ§€μ—μ„œ λ§ˆμ΄νŽ˜μ΄μ§€λ‘œ 그리고 둜그인 νŽ˜μ΄μ§€λ‘œ Stack 이 μŒ“μ—¬μžˆλŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

![protected route {{ w: 1100, h: 780, parentW: 50 }}](/images/protectedRoute/protected-route.png)

μœ„ μƒνƒœμ—μ„œ λ’€λ‘œκ°€κΈ°λ₯Ό ν•˜κ²Œ 되면 Stack 자료 ꡬ쑰의 λ™μž‘ 방식에 따라 μ΅œμƒμœ„ 둜그인 νŽ˜μ΄μ§€κ°€<br />
μ‚¬λΌμ§€κ²Œ λ©λ‹ˆλ‹€. 그럼 마이 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜κ²Œ λ©λ‹ˆλ‹€.

![back history stack {{ w: 980, h: 810, parentW: 50 }}](/images/protectedRoute/back-image.png)

λ¬Έμ œλŠ” 아직 λ‘œκ·ΈμΈμ„ ν•˜μ§€ μ•Šμ•„<br />
마이 νŽ˜μ΄μ§€λ‘œ 이동할 경우 `Protected Route` 에 μ˜ν•΄ λ‹€μ‹œ 둜그인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.<br />

![protected route {{ w: 1100, h: 780, parentW: 50 }}](/images/protectedRoute/protected-route.png)

결과적으둜 λ’€λ‘œ κ°€κΈ°λ₯Ό 해도 μ‚¬μš©μžλŠ” 계속 둜그인 νŽ˜μ΄μ§€λ₯Ό 보게 λ©λ‹ˆλ‹€.<br />
이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ `replace` option 을 ν™œμš©ν–ˆμŠ΅λ‹ˆλ‹€.

### replace?

ProtectedRoute μ»΄ν¬λ„ŒνŠΈ μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

```tsx
import { useRecoilValue } from "recoil";
import { Navigate, Outlet, useLocation } from "react-router-dom";

import { isLoginUserSelector } from "../recoil/user";

function ProtectedRoute() {
const currentLocation = useLocation();
const isLoginUser = useRecoilValue(isLoginUserSelector);

if (!isLoginUser) {
return <Navigate to="/login" replace state={{ from: currentLocation }} />;
} else {
return <Outlet />;
}
}
```

Navigate μ»΄ν¬λ„ŒνŠΈμ—μ„œ `replace` props 을 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.<br />
`replace` 의 역할은 History Stack 의 ν˜„μž¬ ν•­λͺ©μ„ λŒ€μ²΄ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€.<br />

- [react router history docs](https://v5.reactrouter.com/web/api/history)

ν˜„μž¬ ν•­λͺ©μ„ λŒ€μ²΄ν•˜κ²Œ λœλ‹€λŠ” 건 μ•„λž˜μ™€ 같이 정리할 수 μžˆμ„ 것 κ°™μŠ΅λ‹ˆλ‹€.

> 1. λ‘œκ·ΈμΈμ„ ν•˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ 마이 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.<br />
> (History Stack 에 메인 νŽ˜μ΄μ§€, 마이 νŽ˜μ΄μ§€ 순으둜 μŠ€νƒμ΄ μŒ“μ—¬μžˆμŠ΅λ‹ˆλ‹€.)
> 2. `Protected Route` 에 μ˜ν•΄ 둜그인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.<br />
> (replace 에 μ˜ν•΄ 마이 νŽ˜μ΄μ§€ μŠ€νƒμ΄ 둜그인 νŽ˜μ΄μ§€ μŠ€νƒμœΌλ‘œ λŒ€μ²΄λ©λ‹ˆλ‹€.)
μ΄λ ‡κ²Œ 될 경우 μ•„λž˜μ™€ 같은 μŠ€νƒ ꡬ쑰λ₯Ό κ°€μ§€κ²Œ λ©λ‹ˆλ‹€.

![replace {{ w: 1000, h: 770, parentW: 50 }}](/images/protectedRoute/replace.png)

이 μƒνƒœμ—μ„œ λ’€λ‘œ κ°€κΈ°λ₯Ό λˆ„λ₯΄λ©΄ 메인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜λ―€λ‘œ<br />
이전 μ‚¬μš©μžκ°€ λ’€λ‘œ κ°€κΈ°λ₯Ό λˆŒλŸ¬λ„ 계속 둜그인 νŽ˜μ΄μ§€λ₯Ό ν‘œκΈ°ν•˜λŠ” 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

- [kakao location replace ν¬μŠ€νŒ…](https://fe-developers.kakaoent.com/2022/221124-router-without-library/#location-replace)
- [replace method MDN](https://developer.mozilla.org/en-US/docs/Web/API/Location/replace)

### μ‹œλ‚˜λ¦¬μ˜€ 외적 μ²˜λ¦¬ν•  λΆ€λΆ„ - Navigate state

λ‘œκ·ΈμΈμ„ ν•˜μ§€ μ•Šμ€ 경우, λŒ€μ‹œλ³΄λ“œ, λ§ˆμ΄νŽ˜μ΄μ§€λ‘œ 이동 μ‹œ `Protected Route` 에 μ˜ν•΄ login νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.<br />
login νŽ˜μ΄μ§€μ—μ„œ λ‘œκ·ΈμΈμ— 성곡할 경우, μš°λ¦¬λŠ” μ–΄λ””λ‘œ 이동할 κ²ƒμœΌλ‘œ μ˜ˆμƒν• κΉŒμš”?<br />
μ›λž˜ μ ‘μ†ν•˜κ³ μž ν–ˆλ˜ νŽ˜μ΄μ§€λ‘œ 이동할 κ²ƒμœΌλ‘œ μ˜ˆμƒν• κ²λ‹ˆλ‹€.

ν˜„μž¬ κΈ°νšμ„œμ—λŠ” λͺ…μ‹œλ˜μ§€ μ•Šμ•˜μ§€λ§Œ, μ‚¬μš©μž μž…μž₯에선 λ‹Ήμ—°ν•˜κ³  νŽΈλ¦¬ν•œ κΈ°λŠ₯을 κ΅¬ν˜„ν•˜κ³ μž ν•©λ‹ˆλ‹€.<br />
이 κΈ°λŠ₯을 μœ„ν•΄ ν•„μš”ν•œ 점은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

> 1. `Protected Route` 에 μ˜ν•΄ login νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜κΈ° μ „ νŽ˜μ΄μ§€κ°€ 무엇인지 μ•Œμ•„μ•Όν•©λ‹ˆλ‹€.
> 2. 둜그인이 μ™„λ£Œλœ ν›„, 이전 νŽ˜μ΄μ§€(μ›λž˜ κ°€κ³ μž ν–ˆλ˜ νŽ˜μ΄μ§€)둜 이동할 수 μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.<br />
> κ·Έλ ‡λ‹€λ©΄ 이전 νŽ˜μ΄μ§€μ— λŒ€ν•œ 정보λ₯Ό 둜그인 νŽ˜μ΄μ§€μ—μ„œλ„ μ•Œκ³  μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.
μš°λ¦¬λŠ” 이전 `replace` μ˜΅μ…˜μ„ μ‚¬μš©ν•˜λ©΄μ„œ μ›λž˜ λ“€μ–΄κ°€κ³ μž ν–ˆλ˜ νŽ˜μ΄μ§€λ₯Ό History Stack μ—μ„œ<br />
찾을 수 μ—†μŠ΅λ‹ˆλ‹€. 그렇기에 λ‹€λ₯Έ 방법을 λͺ¨μƒ‰ν•΄μ•Όν•©λ‹ˆλ‹€.

κ·Έλ ‡λ‹€λ©΄ replace κ°€ 되기 μ „, ν˜„μž¬ νŽ˜μ΄μ§€μ— λŒ€ν•œ location 정보λ₯Ό κ°€μ Έμ˜€κ³ <br />
login νŽ˜μ΄μ§€λ‘œ κ·Έ 정보λ₯Ό μ „λ‹¬ν•˜λ©΄ 될 것 κ°™μŠ΅λ‹ˆλ‹€.

이λ₯Ό μœ„ν•΄ react-router-dom 라이브러리의 `useLocation` hook 을 ν™œμš©ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.<br />
useLocation hook 은 ν˜„μž¬ location 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. <br />
이λ₯Ό 톡해 ν˜„μž¬ location 정보λ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€.

- [react router useLocation hook docs](https://reactrouter.com/en/main/hooks/use-location)

그리고 location 정보λ₯Ό login νŽ˜μ΄μ§€λ‘œ μ „λ‹¬ν•˜κΈ° μœ„ν•΄ Navigate μ»΄ν¬λ„ŒνŠΈμ˜ state prop 을 ν™œμš©ν•©λ‹ˆλ‹€.<br />
state prop 을 톡해 μ–΄λ–€ μƒνƒœλ₯Ό 이동할 νŽ˜μ΄μ§€λ‘œ 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.<br />
`useLocation`, `Navigate μ»΄ν¬λ„ŒνŠΈμ˜ state prop` 두 가지λ₯Ό ν™œμš©ν•˜μ—¬ μ•„λž˜μ™€ 같이 κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.

```tsx
import { useRecoilValue } from "recoil";
import { Navigate, Outlet, useLocation } from "react-router-dom";

import { isLoginUserSelector } from "../recoil/user";

function ProtectedRoute() {
const currentLocation = useLocation(); // ν˜„μž¬ location 객체 정보λ₯Ό κ°€μ Έμ˜¨λ‹€.
const isLoginUser = useRecoilValue(isLoginUserSelector);

if (!isLoginUser) {
// Navigate μ»΄ν¬λ„ŒνŠΈμ˜ state prop 에 ν˜„μž¬ location 객체λ₯Ό μ „λ‹¬ν•œλ‹€.
return <Navigate to="/login" replace state={{ from: currentLocation }} />;
} else {
return <Outlet />;
}
}
```

그리고 login νŽ˜μ΄μ§€μ—μ„œλŠ” location 객체λ₯Ό μ•„λž˜μ™€ 같이 ν™œμš©ν•©λ‹ˆλ‹€.

```tsx
import { useNavigate, useLocation } from "react-router-dom";

import { useLogin } from "./hooks/login";

import type { FormEvent } from "react";

function Login() {
// ... λ‹€λ₯Έ λΉ„μ¦ˆλ‹ˆμŠ€ μ½”λ“œ
const loginMutation = useLogin();
const location = useLocation();
const navigation = useNavigate();

// useLocation hooks 을 톡해 μ „λ‹¬ν•œ location 의 pathname 을 κ°€μ Έμ˜¨λ‹€.
// λ§Œμ•½ 없을 경우 `/` 메인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•œλ‹€.
const from = location.state?.from?.pathname ?? "/";

const handleLoginSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();

loginMutation.mutate(
{ id, password },
{
onSuccess: (response: { accessToken: string }) => {
// API 호좜이 μ„±κ³΅ν–ˆμ„ 경우, useNavigate hook 을 μ‚¬μš©ν•˜μ—¬ 이동
navigation(from);
},
onError: () => {
alert("둜그인 μ‹€νŒ¨!");
},
}
);
};

return (
<FormWrapper onSubmit={handleLoginSubmit}>
{/** λ‹€λ₯Έ μ»΄ν¬λ„ŒνŠΈ... */}
</FormWrapper>
);
}
```

둜그인이 μ„±κ³΅ν–ˆμ„ 경우, μ „λ‹¬ν•œ location 객체 정보λ₯Ό ν™œμš©ν•˜μ—¬ νŽ˜μ΄μ§€λ₯Ό μ΄λ™ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.<br />
이λ₯Ό 톡해 둜그인 성곡 μ‹œ, μ›λž˜ κ°€κ³ μž ν–ˆλ˜ νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜λŠ” κΈ°λŠ₯ λ˜ν•œ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

### μƒˆλ‘­κ²Œ μ‚¬μš©ν•΄λ³΄κ³  배운 것 - Outlet

`Outlet` 은 react router dom μ—μ„œ μ œκ³΅ν•˜λŠ” μ»΄ν¬λ„ŒνŠΈλ‘œ<br />
쀑첩 λΌμš°νŒ…, 쀑첩 λ ˆμ΄μ•„μ›ƒ (React 의 children κ³Ό 같은) κΈ°λŠ₯으둜 ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

- [react router Outlet docs](https://reactrouter.com/en/main/components/outlet)

곡식 λ¬Έμ„œμ˜ 예제λ₯Ό 보면 μ‚¬μš©λ²•μ„ μ‰½κ²Œ 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

```tsx
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>

{/* This element will render either <DashboardMessages> when the URL is
"/messages", <DashboardTasks> at "/tasks", or null if it is "/"
*/}
<Outlet />
</div>
);
}

function App() {
return (
<Routes>
<Route path="/" element={<Dashboard />}>
<Route path="messages" element={<DashboardMessages />} />
<Route path="tasks" element={<DashboardTasks />} />
</Route>
</Routes>
);
}
```

`/messages`, `/tasks` 둜 이동할 경우, 항상 `<h1>Dashboard</h1>` 와 ν•¨κ»˜ λ„μ›Œμ§€λŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.<br />
`/messages`, `/tasks` router μƒμœ„μ—λŠ” `/` κ°€ 있고, 이 λ–„ Dashboard μ»΄ν¬λ„ŒνŠΈλ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.

그리고 Dashboard μ—μ„œλŠ” λ‚΄λΆ€μ—μ„œλŠ” `Outlet` 을 μ‚¬μš©ν•˜μ—¬ `/messages`, `/tasks` 둜 이동 μ‹œ<br />
싀행될 μ»΄ν¬λ„ŒνŠΈλ₯Ό `Outlet` 의 μœ„μΉ˜μ—μ„œ μ‹€ν–‰ν•©λ‹ˆλ‹€.<br />
μ΄λŸ¬ν•œ νŠΉμ§•μœΌλ‘œ 인해 React 의 children κ³Ό λΉ„μŠ·ν•œ λ™μž‘μ΄λΌκ³  λ§μ”€λ“œλ ΈμŠ΅λ‹ˆλ‹€.

κ·Έλ ‡λ‹€λ©΄ μ΄λŸ¬ν•œ 쀑첩 λΌμš°νŒ…, λ ˆμ΄μ•„μ›ƒμ„ μ œκ³΅ν•˜λŠ” `Outlet` 을 `Protected Route` λ₯Ό κ΅¬ν˜„ν•  λ•Œ μ–΄λ–»κ²Œ<br />
μ‚¬μš©ν–ˆμ„κΉŒμš”? μ΄λŠ” μ•„λž˜ μ½”λ“œμ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

```tsx
// routes/ProtectedRoute.tsx
import { useRecoilValue } from "recoil";
import { Navigate, Outlet, useLocation } from "react-router-dom";

import { isLoginUserSelector } from "../recoil/user";

function ProtectedRoute() {
const currentLocation = useLocation();
const isLoginUser = useRecoilValue(isLoginUserSelector);

if (!isLoginUser) {
return <Navigate to="/login" replace state={{ from: currentLocation }} />;
} else {
return <Outlet />;
}
}
// routes/index.tsx
import { BrowserRouter, Routes, Route } from "react-router-dom";

import Main from "../pages/Main";
import Login from "../pages/Login";
import MyPage from "../pages/MyPage";
import Dashboard from "../pages/Dashboard";
import ProtectedRoute from "./ProtectedRoute";

function Routers() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />} />
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoute />}>
<Route path="/my-page" element={<MyPage />} />
<Route path="/dashboard" element={<Dashboard />} />
</Route>
</Routes>
</BrowserRouter>
);
}
```

`Outlet` 은 `ProtectedRoute` μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.<br />
둜그인이 λ˜μ—ˆμ„ λ•Œ, `<Outlet />` μ»΄ν¬λ„ŒνŠΈλ₯Ό return ν•©λ‹ˆλ‹€.

그리고 Routes μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” μ΄λŸ¬ν•œ `ProtectedRoute` λ₯Ό `/my-page`, `/dashboard` μƒμœ„μ˜<br />
Route 둜 감싼 ν˜•νƒœλ‘œ κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

μš°λ¦¬κ°€ κ΅¬ν˜„ν•œ `ProtectedRoute` λŠ” 둜그인이 λ˜μ§€ μ•Šμ•˜μ„ λ•ŒλŠ” login νŽ˜μ΄μ§€λ‘œ,<br />
둜그인이 λ˜μ—ˆμ„ 땐 μ›λž˜ μ΄λ™ν•˜κ³ μž ν–ˆλ˜ νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜λŠ” 것이 λͺ©μ μž…λ‹ˆλ‹€.<br />
이λ₯Ό `Outlet` 을 톡해 κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.<br />
둜그인이 λ˜μ—ˆμ„ 땐 `Outlet` 을 μ‚¬μš©ν•˜μ—¬ κ·Έ ν•˜μœ„μ— μœ„μΉ˜ν•œ Route μ»΄ν¬λ„ŒνŠΈλ₯Ό 좜λ ₯ν•˜λŠ” λ°©μ‹μœΌλ‘œμš”.

μ΄λ ‡κ²Œ κ΅¬ν˜„ν•˜κ²Œ 될 경우 μ•„λž˜μ™€ 같은 μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.

> 1. λ‹€λ₯Έ Route μ—μ„œ ProtectedRoute 의 κΈ°λŠ₯이 ν•„μš”ν•˜λ‹€λ©΄ λ™μΌν•˜κ²Œ 감싸주면 λœλ‹€.
> 2. 적용이 맀우 쉽고, 각 μ»΄ν¬λ„ŒνŠΈ(ProtectedRoute, μ›λž˜ 좜λ ₯ν•˜κ³ μž ν•˜λŠ” μ½€ν¬λ„ŒνŠΈ)λŠ” 각자 ν• μΌλ§Œ ν•  수 μžˆλ‹€.
> (κ΄€μ‹¬μ‚¬μ˜ 뢄리)
## ν›„κΈ°

Navigate 의 replace 의 경우, μ–΄λ–€ κ²½μš°μ— μ‚¬μš©ν•˜λŠ”μ§€λŠ” μ•Œκ³  μžˆμ—ˆμœΌλ‚˜ μ–΄λ–»κ²Œ λ™μž‘ν•˜λŠ”μ§€<br />
λͺ…ν™•νžˆ μ•Œκ³  μžˆμ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. 이번 기회λ₯Ό 톡해 'λ‚΄κ°€ λͺ¨ν˜Έν•˜κ²Œ μ•Œκ³  μžˆμ—ˆκ΅¬λ‚˜' λΌλŠ” 것을 꺠닫기도 ν–ˆκ΅¬μš”.<br />
μ•„λ¬΄λž˜λ„ ν˜„μ—…μ—μ„œ μœ μ§€λ³΄μˆ˜λ₯Ό ν•˜κ³  있고, 그렇기에 Protected Route 와 같이 μ΄ˆκΈ°μ— μ…‹μ—…ν•˜λŠ” 방식을<br />
직접 μ½”λ“œλ‘œ μ•ˆμ¨λ³Έμ§€ κ½€ λœν„°λΌ λ¦¬λ§ˆμΈλ“œλ₯Ό ν™•μ‹€νžˆ ν•΄λ΄€λ‹€λŠ” μ μ—μ„œ μ–»μ–΄κ°€λŠ” 점이 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

λ˜ν•œ React Router Dom `Outlet` 은 λ“£κΈ°λ§Œ ν–ˆμ—ˆμ§€ μ—¬νƒœ ν™œμš©ν•΄λ³Έ 적이 μ—†μ—ˆκΈ°μ— 도움이 많이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.<br />
쀑첩 λΌμš°νŒ…, λ ˆμ΄μ•„μ›ƒμ΄λΌλŠ” 것이 μ–΄λ–»κ²Œ 도움을 쀄 수 μžˆλŠ”μ§€λ₯Ό μ•Œ 수 μžˆμ—ˆκ³ , 직접 μ‚¬μš©ν•˜λ©΄μ„œ<br />
κ·Έ 원리λ₯Ό νŒŒμ•…ν–ˆλ‹€λŠ” μ μ—μ„œ 쒋은 κ²½ν—˜μ΄λΌκ³  μƒκ°ν•©λ‹ˆλ‹€.
_(ν™•μ‹€νžˆ 직접 μ‚¬μš©ν•΄λ΄μ•Ό μ•Œκ² λ‹€λŠ” 점 λ˜ν•œ λ‹€μ‹œκΈˆ 느끼게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.)_

기술적인 λΆ€λΆ„μ—μ„œ μ–»μ–΄κ°€λŠ” 뢀뢄도 λ§Žμ•˜κ³ , κΈ°μ‘΄ μ‹œλ‚˜λ¦¬μ˜€μ—μ„œ κ°œλ°œμžκ°€ κ΅¬ν˜„ν•˜λ©΄μ„œ 더 생각해봐야할 점을<br />
κ³ λ―Όν•˜λŠ” 뢀뢄도 도움이 많이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€. κΈ°νšμ„œλ₯Ό λΆ„μ„ν•˜κ³ , κ°œλ°œν•˜λ©΄μ„œ λͺ©μ†Œλ¦¬λ₯Ό λ‚΄λŠ” 것이 μ€‘μš”ν•˜κΈ°μ—<br />
μ•„μ£Ό μ‘°κ·Έλ§ˆν•œ μŠ€νŽ™μ—μ„œλΆ€ν„° μƒκ°ν•˜λŠ” μ—°μŠ΅μ„ ν•΄λ΄€λ‹€λŠ” μ μ—μ„œ 쒋은 κ²½ν—˜μ΄λΌκ³  μƒκ°ν•©λ‹ˆλ‹€.

μ‹œλ‚˜λ¦¬μ˜€λŒ€λ‘œ κ΅¬ν˜„ν•˜κ³  끝이 μ•„λ‹Œ, 직접 ν…ŒμŠ€νŠΈν•΄λ³΄λ©΄μ„œ '이건 μ’€ λΆˆνŽΈν•œλ°?', 'λ‹€λ₯Έ 곳은 μ–΄λ–»κ²Œ λ˜μ–΄μžˆμ§€?'<br />
와 같은 μ—°κ²°λœ 생각, μ†”λ£¨μ…˜ μ°ΎκΈ° λ“± 이λ₯Ό μ§€μ†μ μœΌλ‘œ μ²΄λ“ν™”ν•˜λŠ” 것을 λͺ©ν‘œλ‘œ μ—°μŠ΅ν•΄λ³Ό μƒκ°μž…λ‹ˆλ‹€.

## 레퍼런슀

- [react router history docs](https://v5.reactrouter.com/web/api/history)
- [kakao location replace ν¬μŠ€νŒ…](https://fe-developers.kakaoent.com/2022/221124-router-without-library/#location-replace)
- [replace method MDN](https://developer.mozilla.org/en-US/docs/Web/API/Location/replace)
- [react router useLocation hook docs](https://reactrouter.com/en/main/hooks/use-location)
- [react router Outlet docs](https://reactrouter.com/en/main/components/outlet)
Binary file added public/images/protectedRoute/back-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/protectedRoute/protected-route.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/protectedRoute/replace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/protectedRoute/thumbnail.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

1 comment on commit 2f7c34d

@vercel
Copy link

@vercel vercel bot commented on 2f7c34d Jun 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

takhyun-dev – ./

takhyun-dev-git-main-takhyunkim.vercel.app
takhyun-dev-takhyunkim.vercel.app
takhyun.dev

Please sign in to comment.