-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
전남대 FE_임지환 2주차 과제 #51
Open
dlawlghks
wants to merge
32
commits into
kakao-tech-campus-2nd-step2:dlawlghks
Choose a base branch
from
dlawlghks:jihwan
base: dlawlghks
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 23 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
967ebf5
chore: 패키지 업데이트
dlawlghks 6009648
feat: 필요한 이미지 추가
dlawlghks dbf67d4
refactor: App 컴포넌트를 AuthProvider와 AppRoutes 포함하도록 수정
dlawlghks b9b2447
feat: Header 컴포넌트 추가
dlawlghks 91f0eae
feat: Footer 컴포넌트 추가
dlawlghks d59ab6d
feat: 선물랭킹 페이지 추가
dlawlghks 11ca227
feat: SuggestBanner 컴포넌트 추가
dlawlghks 816e095
feat: FriendBanner 컴포넌트 추가
dlawlghks 9222908
feat: HomePage 컴포넌트 추가
dlawlghks 5a9311c
feat: 로그인 페이지 컴포넌트 추가
dlawlghks c101c52
feat: 라우터 설정 및 페이지 경로 추가
dlawlghks 9f8e263
faet: 경로 설정을 위한 Path 추가
dlawlghks 8942cd9
feat: ProductList 컴포넌트 추가 및 필터링 기능 구현
dlawlghks a83c77d
feat: ThemePage 컴포넌트 추가
dlawlghks 7ed1f3d
feat: Category 컴포넌트 추가
dlawlghks 088a1fa
feat: AgeTabs 컴포넌트 추가
dlawlghks d34f8e8
feat: TypeTabs 컴포넌트 추가
dlawlghks 27dccba
feat: 내 계정 페이지 컴포넌트 추가
dlawlghks c9737bc
feat: 제목, 설명, 배경색 설정 가능한 HeaderSection 컴포넌트 추가
dlawlghks c6944e0
feat: 로그인을 위한 ProtectedRoute 추가
dlawlghks dba85c2
feat: AuthContext 추가 및 로그인/로그아웃 기능 구현
dlawlghks 7fd0e88
docs: README 업데이트 및 요구 사항과 질문 답변 추가
dlawlghks f18d957
fix: 로그인 후 이전 페이지로 리디렉션 문제 수정
dlawlghks 3e182ad
refactor: Layout 및 ProtectedRoute 컴포넌트를 사용하여 라우터 설정 리팩토링
dlawlghks 18c2531
refactor: useContext의 타입 명시적으로 지정하여 타입 안전성 개선
dlawlghks 745ccb3
refactor: Props를 interface로 변경하여 ComponentProps<'div'> 확장
dlawlghks 340361e
refactor: useState 초기값을 필터링된 제품 리스트로 설정
dlawlghks cac8959
refactor: visibleProducts 상태를 isCollapsed 상태로 대체
dlawlghks 2fe96be
refactor: TypeTabs 컴포넌트와 GiftRankingPage 컴포넌트의 activeType 타입을 구체적으로 지정
dlawlghks 40e5293
refactor: 바로 로그인으로 이동하도록 수정
dlawlghks a465bb7
refactor: 불필요한 코드 제거
dlawlghks 7309b24
refactor: 로그인 후 리디렉션 경로 설정 간소화
dlawlghks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,165 @@ | ||
# 카카오 테크 캠퍼스 - 프론트엔드 카카오 선물하기 편 | ||
|
||
[🔗 link](https://edu.nextstep.camp/s/hazAC9xa) | ||
## 🚀 1단계 - 페이지 만들기 (without. API) | ||
|
||
## Week 1. 1단계 - 프로젝트 세팅 | ||
### 진행 방식 | ||
|
||
[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/QzgHvzRM) | ||
- 미션은 과제 진행 요구 사항, 기능 요구 사항, 프로그래밍 요구 사항 세 가지로 구성되어 있다. | ||
- 세 개의 요구 사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다. | ||
- 기능 요구 사항에 기재되지 않은 내용은 스스로 판단하여 구현한다. | ||
|
||
## Week 1. 2단계 - Storybook을 사용하여 재사용 가능한 컴포넌트 구현 | ||
### 📝 Requirements | ||
|
||
[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/4wYFPW1K) | ||
- 본인만의 기준으로 일관된 코드를 작성해주세요. | ||
- 기능 단위로 나누어 커밋을 해주세요. | ||
H- eader, Footer와 같은 공통 컴포넌트를 만들어요. (모든 페이지에서 Header와 Footer는 보여질 수 있게 적용해요.) | ||
- 각 Url Path별로 페이지를 만들어요. (결과물과 스타일은 결과 링크 참고) | ||
- 메인 페이지 (/) | ||
- Theme 카테고리 섹션을 추가해요. | ||
- Theme 카테고리 Item을 클릭 시 Theme 페이지(/theme/:themeKey)로 이동해요. | ||
- 실시간 급상승 선물랭킹을 추가해요. | ||
- 필터 기능을 hooks를 사용하여 구현해요. (ex. 전체, 여성이, 남성이, 청소년이 / 받고 싶어한, 많이 선물한, 위시로 받은) | ||
- 상품 목록을 처음에는 6개만 보여지게 해요. 더보기를 누르는 경우 상품 목록을 더 보여줘요. (접기 버튼을 누르면 다시 6개만 보여지게 해요) | ||
- Theme 페이지(/theme/:themeKey) | ||
- Header 섹션을 추가해요. | ||
- 재사용성을 고려하여 Header 섹션을 만들어요. (themeKey에 따라 label, title, description, backgroundColor가 달라짐) | ||
- 상품 목록 섹션을 추가해요. | ||
- 로그인 페이지(/login) | ||
- ID와 PW를 입력하면 로그인이 되도록 구현해요. (ID와 PW는 아무 값을 입력해도 통과되도록 해요.) | ||
- 나의 페이지(/my-account) | ||
- 로그아웃을 할 수있는 버튼을 추가해요. | ||
|
||
## Week 2. 1단계 - 페이지 만들기 | ||
## 🚀 2단계 - 인증 프로세스 구현 | ||
|
||
[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/QzV1ncxk) | ||
### 🚀 Getting Started | ||
|
||
✔️ ContextAPI의 사용법과 어떨때 사용하면 좋을지 생각해봐요. | ||
<br>✔️ SessionStorage, LocalStorage, Cookie의 차이에 대해 살펴보고 각각 어떨때 사용하면 좋을지 고민해요. | ||
|
||
### 📝 Requirements | ||
|
||
- 본인만의 기준으로 일관된 코드를 작성해주세요. | ||
- 기능 단위로 나누어 커밋을 해주세요. | ||
- 로그인 페이지에서 ID와 PW를 입력하면 직전 페이지로 Redirect 되도록 해요. | ||
- Fake 로그인 기능을 구현해요. | ||
- 로그인 페이지에서 ID와 PW를 입력하면 ID를 sessionStorage의 authToken key에 저장해요. | ||
- 모든 페이지 진입 시 authToken을 토대로 로그인 여부를 판단하는 로직을 추가해요. (ContextAPI 활용) | ||
- Header에서 로그인 한 경우 내 계정을 로그인 하지 않은 경우 로그인 버튼을 추가해요. | ||
- 내 계정(/my-account) 페이지는 로그인 한 사람만 접근 가능하게 해요. (로그인 하지 않은 유저는 로그인 페이지로 연결해요) | ||
- 내 계정 페이지에서 로그아웃을 할 수 있도록 해요. (로그아웃 후 메인 페이지(/) 로 Redirect 되도록 해요) | ||
|
||
## 🚀 3단계 - 질문의 답변을 README에 작성 | ||
|
||
### 📝 Requirements | ||
|
||
### 2주차 질문 | ||
|
||
### 질문 1. CRA 기반의 SPA프로젝트에서 React Router를 사용하지 않는다면 어떤 문제가 발생하나요? | ||
|
||
#### CRA(Create React App) 기반의 SPA(Single Page Application) 프로젝트에서 React Router를 사용하지 않는다면 다양한 문제가 발생할 수 있다. | ||
|
||
1. 페이지 간 네비게이션 문제 | ||
|
||
- SPA는 단일 HTML 파일로 여러 페이지를 구성한다. | ||
- React Router 없이 페이지 간 전환을 수동으로 처리해야 하므로 복잡하고 오류가 발생하기 쉽다. | ||
- URL에 따라 페이지를 렌더링하는 기능이 없기 때문에, 사용자 경험이 저하되고 애플리케이션의 구조가 혼란스러워질 수 있다. | ||
|
||
2. 상태 관리의 복잡성 증가 | ||
|
||
- URL에 따라 다른 상태를 유지하고 관리해야 하는 경우, 이를 수동으로 구현하는 것은 매우 복잡하고 유지보수가 어렵다. | ||
- 페이지 전환 시 필요한 데이터를 관리하는 로직을 직접 구현해야 - 하므로 코드가 복잡해지고 버그가 발생할 가능성이 높아진다. | ||
|
||
3. 뒤로가기/앞으로가기 기능의 비활성화 | ||
|
||
- 브라우저의 기본 네비게이션 기능(뒤로가기, 앞으로가기)을 사용할 수 없게 되어 사용자 경험이 저하된다. | ||
- 수동으로 브라우저의 히스토리를 관리해야 하는 추가적인 복잡성이 생긴다. | ||
|
||
4. URL과 상태 동기화 문제 | ||
|
||
- React Router는 URL과 애플리케이션 상태를 동기화하여 사용자가 브라우저의 주소창에 직접 URL을 입력하거나 북마크를 사용하는 경우에도 올바른 페이지가 렌더링되도록 한다. | ||
- React Router 없이 이를 구현하려면 많은 수작업이 필요하며, 잘못 구현할 경우 애플리케이션이 비정상적으로 동작할 수 있다. | ||
|
||
5. 코드 분할(Code Splitting)과 최적화 문제 | ||
|
||
- React Router는 코드 분할을 쉽게 구현할 수 있는 기능을 제공한다. | ||
- 이를 통해 초기 로딩 시간을 줄이고, 필요한 시점에만 필요한 코드가 로드되도록 할 수 있다. | ||
- React Router 없이 이러한 최적화를 수동으로 구현하기는 매우 어렵고, 성능 저하가 발생할 수 있다. | ||
|
||
6. 동적 라우팅 및 중첩 라우팅 문제 | ||
|
||
- React Router는 동적 라우팅과 중첩 라우팅을 간편하게 설정할 수 있는 기능을 제공한다. | ||
- 이를 통해 복잡한 네비게이션 구조를 쉽게 구현할 수 있지만, React Router 없이 이를 수동으로 처리하려면 많은 노력이 필요하며, 유지보수가 어려워진다. | ||
|
||
### 질문 2. 리액트 Context 나 Redux는 언제 사용하면 좋을까요? (로그인을 제외한 예시와 이유를 함께 적어주세요.) | ||
|
||
💡 리액트 Context와 Redux는 전역 상태 관리를 위해 사용된다. 각각의 사용 사례와 장점을 이해하면, 어느 상황에서 이 도구들을 사용하는 것이 적절한지 알 수 있다. | ||
|
||
**리액트 Context 사용 시기와 예시** | ||
|
||
리액트 Context는 비교적 간단한 상태 공유가 필요할 때 유용하다. | ||
|
||
1. 테마 관리 | ||
- 다크모드와 라이트 모드를 지원하는 애플리케이션에서 사용자가 선택한 테마를 전역적으로 관리할 때 | ||
- 테마 정보는 애플리케이션의 여러 컴포넌트에서 필요할 수 있다. Context를 사용하면 테마 정보를 쉽게 공유하고 업데이트할 수 있다. | ||
2. 언어 설정 | ||
- 다국어 지원 애플리케이션에서 사용자가 선택한 언어 설정을 관리할 때 | ||
- 언어 설정은 애플리케이션의 모든 컴포넌트에서 접근해야 하므로 Context를 사용하여 전역적으로 관리할 수 있다. | ||
3. 사용자 환경 설정 | ||
- 사용자 인터페이스의 레이아웃, 폰트 크기, 색상 등을 사용자 지정할 수 있도록 하는 경우 | ||
- 사용자 설정은 여러 컴포넌트에서 접근하고 수정할 수 있어야 하므로 Context를 사용하여 효율적으로 관리할 수 있다. | ||
|
||
**Redux 사용 시기와 예시** | ||
|
||
Redux는 복잡한 상태 관리가 필요한 경우에 유용하다. | ||
|
||
1. 대규모 애플리케이션의 상태 관리 | ||
- 대규모 전자 상거래 애플리케이션에서 쇼핑 카트, 사용자 정보, 제품 목록 등을 관리할 때 | ||
- Redux는 복잡한 상태 관리를 단순화하고, 상태 변경을 예측 가능하게 하며, 상태를 쉽게 디버깅할 수 있게 도와준다. | ||
2. 공유 상태가 많은 복잡한 컴포넌트 트리 | ||
- 대규모 대시보드 애플리케이션에서 여러 위젯들이 서로 다른 데이터를 공유하고 사용하는 경우 | ||
- edux를 사용하면 상태를 중앙에서 관리하고, 복잡한 컴포넌트 트리에서도 상태를 쉽게 전달할 수 있다. | ||
|
||
### 결론 | ||
|
||
- **리액트 Context**는 비교적 간단한 상태 공유가 필요할 때 유용하며, 테마 관리, 언어 설정, 사용자 환경 설정과 같은 경우에 적합하다. | ||
- **Redux**는 복잡한 상태 관리가 필요한 경우에 유용하며, 대규모 애플리케이션, 서버 상태 관리, 상태 변경 로깅 및 디버깅, 공유 상태가 많은 복잡한 컴포넌트 트리에서 적합하다. | ||
|
||
### 질문 3. Local Storage, Session Storage 와 Cookies의 차이가 무엇이며 각각 어떨때 사용하면 좋을까요? | ||
|
||
**Local Storage** | ||
|
||
- **특징** | ||
- 브라우저에 영구적으로 저장되는 데이터. | ||
- 만료 기간이 없으며, 사용자가 명시적으로 데이터를 삭제하지 않는 한 유지된다. | ||
- 약 5MB의 용량 제한이 있다. | ||
- **사용 시기** | ||
- 사용자 설정, 테마, 즐겨찾기 등 장기적으로 유지해야 하는 데이터를 저장할 때 사용하면 좋다. | ||
- 로그인 상태를 유지하기 위해 토큰을 저장할 때 사용하면 좋다. | ||
|
||
**Session Storage** | ||
|
||
- **특징** | ||
- 브라우저 세션 동안만 유지되는 데이터. | ||
- 브라우저 창이나 탭을 닫으면 데이터가 삭제된다. | ||
- 약 5MB의 용량 제한이 있다. | ||
- **사용 시기** | ||
- 페이지 새로고침 시에도 유지되어야 하지만, 브라우저를 닫으면 삭제되어야 하는 데이터를 저장할 때 사용하면 좋다. | ||
- 일회성 로그인 정보나 일시적인 폼 데이터 등을 저장할 때 사용하면 좋다. | ||
|
||
**Cookies** | ||
|
||
- **특징** | ||
- 서버와 클라이언트 간의 작은 데이터 조각을 주고받을 때 사용된다. | ||
- 만료 기간을 설정할 수 있으며, 설정된 기간 동안 유지된다. | ||
- 각 쿠키의 용량은 4KB로 제한되며, 도메인당 최대 20개의 쿠키를 저장할 수 있다. | ||
- HTTP 요청 시 자동으로 서버에 전송된다. | ||
- **사용 시기** | ||
- 세션 관리, 사용자 인증 등 서버와 클라이언트 간의 상태를 유지해야 할 때 사용하면 좋다. | ||
- 사용자 추적 및 광고 목적으로 데이터를 저장할 때 사용하면 좋다. | ||
- 서버에서 데이터를 설정하고 클라이언트에서 자동으로 읽어야 하는 경우 사용하면 좋다. | ||
|
||
### 결론 | ||
|
||
- **Local Storage**는 장기적으로 유지해야 하는 데이터를 저장할 때 적합하다. | ||
- **Session Storage**는 브라우저 세션 동안만 유지해야 하는 데이터를 저장할 때 적합하다. | ||
- **Cookies**는 서버와 클라이언트 간의 상태를 유지하거나 사용자 인증, 추적 목적으로 데이터를 저장할 때 적합하다. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import type { ReactNode} from 'react'; | ||
import { createContext, useContext, useEffect, useState } from 'react'; | ||
|
||
interface AuthContextType { | ||
isLoggedIn: boolean; | ||
user: string | null; | ||
login: (username: string) => void; | ||
logout: () => void; | ||
} | ||
|
||
const AuthContext = createContext<AuthContextType>({ | ||
isLoggedIn: false, | ||
user: null, | ||
login: () => {}, | ||
logout: () => {}, | ||
}); | ||
|
||
export const useAuth = () => useContext(AuthContext); | ||
|
||
interface AuthProviderProps { | ||
children: ReactNode; | ||
} | ||
|
||
export const AuthProvider = ({ children }: AuthProviderProps) => { | ||
const [isLoggedIn, setIsLoggedIn] = useState(false); | ||
const [user, setUser] = useState<string | null>(null); | ||
|
||
useEffect(() => { | ||
const token = sessionStorage.getItem('authToken'); | ||
if (token) { | ||
setIsLoggedIn(true); | ||
setUser(token); | ||
} | ||
}, []); | ||
|
||
const login = (username: string) => { | ||
sessionStorage.setItem('authToken', username); | ||
setIsLoggedIn(true); | ||
setUser(username); | ||
}; | ||
|
||
const logout = () => { | ||
sessionStorage.removeItem('authToken'); | ||
setIsLoggedIn(false); | ||
setUser(null); | ||
}; | ||
|
||
return ( | ||
<AuthContext.Provider value={{ isLoggedIn, user, login, logout }}> | ||
{children} | ||
</AuthContext.Provider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import type { ReactNode } from 'react'; | ||
import { Navigate, useLocation } from 'react-router-dom'; | ||
|
||
import { useAuth } from '@/App-core/AuthContext'; | ||
|
||
interface ProtectedRouteProps { | ||
children: ReactNode; | ||
} | ||
|
||
const ProtectedRoute = ({ children }: ProtectedRouteProps) => { | ||
const { isLoggedIn } = useAuth(); | ||
const location = useLocation(); | ||
|
||
if (!isLoggedIn) { | ||
sessionStorage.setItem('redirectPath', location.pathname + location.search); // 현재 경로 저장 | ||
return <Navigate to="/login" replace />; | ||
} | ||
|
||
return <>{children}</>; | ||
}; | ||
|
||
export default ProtectedRoute; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.