Skip to content
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주차 STEP2, 3 #53

Open
wants to merge 33 commits into
base: dandamdandam
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
98339e6
style: change a tab size 2 to 4
dandamdandam Jul 3, 2024
1076afa
feat: add footer component
dandamdandam Jul 3, 2024
9298084
style: adjust prettier
dandamdandam Jul 3, 2024
021176c
feat: add Header UI
dandamdandam Jul 3, 2024
89a439e
feat: add route(react-router-dom)
dandamdandam Jul 3, 2024
3faa1eb
feat: add themeList (mainpage)
dandamdandam Jul 4, 2024
25a75ff
feat: add themeBtn (mainpage)
dandamdandam Jul 4, 2024
0629ca5
feat: modify reset.css
dandamdandam Jul 4, 2024
11adaee
refactor: split main(page) into main and themeList
dandamdandam Jul 4, 2024
951443e
feat: add targetTypeFilter (mainPage)
dandamdandam Jul 4, 2024
1a60619
refactor: move FilterType.ts
dandamdandam Jul 4, 2024
14c4c2e
feat: modify theme style
dandamdandam Jul 4, 2024
e170617
feat: add rankTypeFilter (mainPage)
dandamdandam Jul 4, 2024
c067b72
feat: add rankingItem List (mainPage)
dandamdandam Jul 4, 2024
d182d67
feat: add toggle detail of rankingItems list (mainPage)
dandamdandam Jul 4, 2024
e8bb0eb
feat: complete mainPage layout and styling
dandamdandam Jul 4, 2024
ac37a25
fix: theme routing error & add error handling
dandamdandam Jul 4, 2024
ebca827
feat: add header section (ThemePage)
dandamdandam Jul 5, 2024
b9b0a0e
feat: add item list section (ThemePage)
dandamdandam Jul 5, 2024
6c4babb
feat: header button router (Header Comp)
dandamdandam Jul 5, 2024
b5ac02e
feat: add login page
dandamdandam Jul 5, 2024
8b6ab4c
feat: add my-account page
dandamdandam Jul 5, 2024
0b0c146
docs: update readme
dandamdandam Jul 5, 2024
4ee8bbe
Update README.md
dandamdandam Jul 5, 2024
b081fbc
style: change sessionStorageKey user to authToken
dandamdandam Jul 5, 2024
7f2357b
feat: add AuthContext
dandamdandam Jul 5, 2024
3301f37
feat: check auth using AuthContext
dandamdandam Jul 5, 2024
560ecc2
docs: update readme
dandamdandam Jul 5, 2024
123769f
feat: update README for step3
dandamdandam Jul 5, 2024
a3f03c0
refactor: rename footar, isDetail -> footer, showMoreDetail
dandamdandam Jul 8, 2024
da421d2
refactor: use array method instead of for
dandamdandam Jul 8, 2024
6859fca
refactor: rename Btn to Button
dandamdandam Jul 8, 2024
907eb61
feat: remove ignore lint rule
dandamdandam Jul 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/.vscode
/node_modules

README.md
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"singleQuote": true,
"semi": true,
"tabWidth": 2,
"tabWidth": 4,
"trailingComma": "all",
"printWidth": 100,
"arrowParens": "always"
Expand Down
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"esbenp.prettier-vscode"
]
}
85 changes: 78 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,86 @@
# 카카오 테크 캠퍼스 - 프론트엔드 카카오 선물하기 편

[🔗 link](https://edu.nextstep.camp/s/hazAC9xa)
## project structure

## Week 1. 1단계 - 프로젝트 세팅
이 프로젝트는 카카오 테크 캠퍼스의 프론트엔드 카카오 선물하기 편 프로젝트입니다. 다음은 프로젝트의 주요 디렉토리 및 파일 구조에 대한 설명입니다.

[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/QzgHvzRM)
- `src/`: 소스 코드가 위치하는 디렉토리입니다. 주요 하위 디렉토리 및 파일은 다음과 같습니다.
- `components/`: 재사용 가능한 컴포넌트들이 위치하는 디렉토리입니다.
- `common/`: 공통 컴포넌트들이 위치하는 디렉토리입니다.
- `Footer/`, `Header/`: 푸터 및 헤더 컴포넌트가 위치하는 디렉토리입니다.
- `context/`: 상태 관리 로직이 위치하는 디렉토리입니다.
- `pages/`: 각 페이지 컴포넌트들이 위치하는 디렉토리입니다. 로그인, 메인 페이지 등이 포함됩니다.
- `styles/`: 전역 스타일 및 CSS 변수가 정의된 파일들이 위치하는 디렉토리입니다.
- `App.tsx`, `index.tsx`: 애플리케이션의 진입점 및 루트 컴포넌트 파일입니다.

## Week 1. 2단계 - Storybook을 사용하여 재사용 가능한 컴포넌트 구현
## page

[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/4wYFPW1K)
|메인|테마|
|---|---|
|![localhost_3000_](https://github.com/dandamdandam/react-gift-ui-flow/assets/102032954/df2712af-c58d-40ff-99d3-c1d036bac3a0)|![localhost_3000_ (1)](https://github.com/dandamdandam/react-gift-ui-flow/assets/102032954/090a2a21-90a4-4101-a52a-a33235de23ed)|
|로그인|마이페이지|
|![image](https://github.com/dandamdandam/react-gift-ui-flow/assets/102032954/cfaa18c0-04ba-42b2-a6bd-03c4376c3e0f)|![image](https://github.com/dandamdandam/react-gift-ui-flow/assets/102032954/a6ae9247-29cd-4b5d-9a9b-2e9c6374e72a)|

## Week 2. 1단계 - 페이지 만들기
## 과제 3단계

[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/QzV1ncxk)
### 질문 1. CRA 기반의 SPA프로젝트에서 React Router를 사용하지 않는다면 어떤 문제가 발생하나요?

- UX적 필요에 따라(1. 사용자는 URL을 통한 페이지 이동에 익숙하다 | 2. 한 페이지에 정보가 너무 많으면 사용하기 불편하기 때문에 페이지는 나누어져 있어야 한다), 브라우저의 페이지 라우팅을 필수 불가결 합니다.
- React Router를 사용하지 않는다면 HISTORY API를 이용해 직접 구현을 해야하는데, 이때 아래와 같은 문제가 발생합니다.
1. 페이지 전환마다 새로고침이 됨: React의 장점 중 하나는 페이지를 전체 랜더링하지 않고 변화를 적용할 수 있다는 점입니다. 하지만 라우터를 사용하지 않으면, 페이지 전환 시 이 장점을 살릴 수 없게 됩니다.
2. 코드의 복잡성이 늘어납니다. React router는 useNavigate 호출하나로 페이지 변환이 가능한 반면, history의 경우 페이지 간 이동의 상태를 관리하고, 뒤로 가기/앞으로 가기를 위한 로직을 관리해주어야 합니다.

### 질문 2. 리액트 Context 나 Redux는 언제 사용하면 좋을까요? (로그인을 제외한 예시와 이유를 함께 적어주세요.)

- 페이지 전반에 필요한 설정: 테마 설정, 언어 선택
- 모든 페이지 컨텐츠에 영향을 미치는 설정의 경우, props로 넘기는 것 보다 전역상태로 관리하는 것이 좋을 것 같습니다.
- props drilling이 일정 이상 넘어간 경우
- 서버에서 불러온 정보 저장
- 같은 정보를 자주 불러오는 것을 방지하기 위해 전역상태로 저장해두는 경우가 많은 것 같습니다.
- 이 경우 정보가 변할 경우 다시 가져오기 위해 서버 전역 상태 관리 라이브러리를 씁니다.

### 질문 3. Local Storage, Session Storage 와 Cookies의 차이가 무엇이며 각각 어떨때 사용하면 좋을까요?

- 🍪 Cookie
- 도메인 단위로 데이터를 저장할 수 있는 장소
- 일반적으로 최대 20개 및 4KB 제한
- 영구 저장 X
- 쿠키 SET: `document.cookie = ‘데이터이름=값’`으로 설정할 수 있다.
- 추가 옵션
- domain: 유효 도메인 설정
- path: 유효 경로 설정
- expires: 만료 날짜 설정
- UTC(표준시)로 작성해야 한다!
- Date.toUTCString() 사용하기.
- max-age: 만료 타이머 설정
- ex) `a=1; domain=127.0.0.1; path=/abc; max-age=3;` localhost/abc에서만 유효한 a=1 데이터가 쿠키에 저장되고, 3초 후에 사라진다.
- ex) `b=2; expires=${new Date(2002, 11, 16).toUTCString()}` b=2 데이터가 쿠키에 저장되고, 날짜가 지나면 사라진다.
- 쿠키 GET: document.cookie는 저장되어 있는 데이터를 세미콜론으로 나누어 리턴한다.
- ex) a=1, b=2가 저장되어 있다면, 반환되는 문자열은 `a=1; b=2`
- 🍪 Storage
- 도메인 단위 저장
- 5MB 제한 (Cookie보다 훨씬 큼)
- 세션 혹은 영구 저장 O
- **sessionStorage**: 브라우저 세션이 유지는 동안 저장
- **localStorage**: 영구 저장
- 위 두 객체의 사용 메소드는 같다.
- 값은 문자열 형태로 저장된다.
- 스토리지 SET: `localStorage.setItem('데이터이름', 데이터 값)`으로 설정 가능
- 스토리지 GET: `localStorage.getItem('데이터 이름')`으로 get
- 스토리지 DEL: `localStorage.removeItem('데이터 이름')` 또는 `localStorage.clear()`

## 🎸

### 과제 수행 일지

- [프로젝트 세팅 및 react-router-dom 추가](https://www.notion.so/Day-8-17d5af7315af4ad8a9b5dd72da8d52b8?pvs=4#f4809a6fe3bf4546be35fb7c72513dbf)
- [메인페이지 테마섹션 구현, 실시간 급상승 선물랭킹 구상](https://www.notion.so/Day-9-4ab00c0835fd4171b27ba7e21a3e81d1?pvs=4#ed06422429ae481487a706b9cbbe26b6)
- [나머지 페이지(theme, 로그인, 마이페이지) 구현](https://www.notion.so/Day-10-f35d03c898934bff9edbf4f150db8104?pvs=4#2be7062e72e543b89d5803e6aa13bb44`)

### 궁금한 점

- 같이 편집되는 빈도 수가 높은 것 끼리 묶으려 하니까 컴포넌트를 page에 두어야 할지 component에 두어야 할지 판단이 잘 서지 않습니다.
- 전역적으로 사용되는 component만 component에 넣으면 되는 걸까요?
- RankingView같은 경우에는 타입선언 파일마저 한 폴더에 넣었는데, 많이 낮선구조로 보이나요..?
- 스타일을 지정할 때 flex에 많이 의존하는 편인데, 성능저하가 되거나 코드의 가독성이 떨이지는 등의 문제는 없을까요?
- ~~authToken의 경우 로그인확인을 할 때 sessionStorage.getItem을 직접 호출해서 하는 것도 문제가 없고 오히려 더 간단한데, 왜 ContextAPI를 쓸까? (어떤 점에서 이점이 있는지 찾아보기~!)~~
58 changes: 57 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
]
},
"dependencies": {
"@emotion/css": "^11.11.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-router-dom": "^6.24.1"
},
"devDependencies": {
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"@craco/craco": "^7.1.0",
"@emotion/eslint-plugin": "^11.11.0",
"@storybook/addon-essentials": "^7.6.17",
Expand Down Expand Up @@ -65,8 +65,10 @@
"eslint-plugin-storybook": "^0.8.0",
"prettier": "^3.2.5",
"prop-types": "^15.8.1",
"react-scripts": "5.0.1",
"storybook": "^7.6.17",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^4.9.5",
"webpack": "^5.90.3"
},
"overrides": {
Expand Down
56 changes: 44 additions & 12 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
import styled from '@emotion/styled';
import { useEffect, useState } from 'react';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

import Footer from './components/Footer';
import AuthContext from './context/AuthContext';
import Error from './pages/Error';
import Login from './pages/Login';
import Main from './pages/Main';
import MyAccount from './pages/MyAccount';
import Theme from './pages/Theme';

const App = () => {
const name = 'Josh Perez';
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
useEffect(() => {
const authToken = sessionStorage.getItem('authToken');
setIsAuthenticated(!!authToken);
}, [isAuthenticated]);

return (
<div>
<Title>Hello, {name}</Title>
</div>
);
return (
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
<RouterProvider router={router} />
<Footer />
</AuthContext.Provider>
);
};

export default App;
const router = createBrowserRouter([
{
path: '/',
element: <Main />,
},
{
path: '/login',
element: <Login />,
},
{
path: '/my-account',
element: <MyAccount />,
},
{
path: '/error/:http_status',
element: <Error />,
},
{
path: '/theme/:themeKey',
element: <Theme />,
},
]);

const Title = styled.h1`
font-size: 1.5em;
color: gray;
`;
export default App;
18 changes: 18 additions & 0 deletions src/components/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from '@emotion/styled';

import { Grid } from '../common/layouts/Grid';

export default () => {
return (
<Footer>
<Grid columns={2}>
<div>카카오톡 선물하기</div>
</Grid>
</Footer>
);
};

const Footer = styled.footer({
padding: '28px 16px 88px',
backgroundColor: 'rgb(250, 250, 252)',
});
60 changes: 60 additions & 0 deletions src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { css } from '@emotion/css';
import styled from '@emotion/styled';
import { useContext } from 'react';
import type { NavigateFunction } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import AuthContext from '@/context/AuthContext';

import { Image } from '../common/Image';

export default () => {
const navigate = useNavigate();

return (
<div>
<header className={headerStyle}>
<FlexContainer>
<Image
alt={'카카오 선물하기 로그인'}
src={'https://gift-s.kakaocdn.net/dn/gift/images/m640/pc_gift_logo.png'}
height={'54px'}
onClick={() => navigate('/')}
/>
<UserButton navigate={navigate} />
</FlexContainer>
</header>
<div
className={css`
height: 54px;
`}
></div>
</div>
);
};

const headerStyle = css`
position: fixed;
width: 100%;
background-color: #ffffff;
`;
const FlexContainer = styled.div({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0px 20px',
});

const UserButton = ({ navigate }: { navigate: NavigateFunction }) => {
const isAuthenticated = useContext(AuthContext).isAuthenticated;

return (
<div>
{isAuthenticated ? (
<button onClick={() => navigate('/my-account')}>내 계정</button>
) : (
<button onClick={() => navigate('/login')}>로그인</button>
)}
</div>
);
};
Loading