-
Notifications
You must be signed in to change notification settings - Fork 0
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
3조 과제 제출 (이정우, 이시우, 문현수, 문대현) #7
base: main
Are you sure you want to change the base?
Conversation
// 사진들 | ||
import jw from '@/assets/profileImage/jw.jpg'; | ||
import sw from '@/assets/profileImage/sw.png'; | ||
import hs from '@/assets/profileImage/hs.jpg'; | ||
import dh from '@/assets/profileImage/dh.png'; | ||
|
||
export const API_BASE_URL = 'https://chickenlecture.xyz'; | ||
|
||
// 사이드바 메뉴 아이템 | ||
import { | ||
CarryOutOutlined, | ||
AreaChartOutlined, | ||
SmileOutlined, | ||
} from '@ant-design/icons'; | ||
|
||
export const SIDEBAR_ITEMS = [ | ||
{ label: '소비기록', href: '/', icon: CarryOutOutlined }, | ||
{ label: '소비통계', href: '/statistics', icon: AreaChartOutlined }, | ||
{ label: 'ABOUT', href: '/about', icon: SmileOutlined }, | ||
]; | ||
|
||
// 통계페이지에서 월구간 옵션 | ||
export const MONTH_RANGE_OPTIONS = [ | ||
{ value: '6', label: '최근 6개월' }, | ||
{ value: '12', label: '최근 12개월' }, | ||
{ value: '18', label: '최근 18개월' }, | ||
{ value: '24', label: '최근 24개월' }, | ||
]; | ||
|
||
// 어바웃 페이지 팀원 소개 | ||
export const TEAM_MEMBERS = [ | ||
{ | ||
name: '이정우', | ||
github: 'https://github.com/howooking', | ||
imgUrl: jw, | ||
roles: ['팀장', '소비통계', '호우킹'], | ||
comment: '수학의 정석 한권', | ||
}, | ||
{ | ||
name: '이시우', | ||
github: 'https://github.com/cuconveniencestore', | ||
imgUrl: sw, | ||
roles: ['소비 CRUD', 'CU편의점', '모범생'], | ||
comment: '24시간이 모자라', | ||
}, | ||
{ | ||
name: '문현수', | ||
github: 'https://github.com/96uoow', | ||
imgUrl: hs, | ||
roles: ['달력', '개블리셔'], | ||
comment: '자바스크립트 쉽다', | ||
}, | ||
{ | ||
name: '문대현', | ||
github: 'https://github.com/dhmoon11', | ||
imgUrl: dh, | ||
roles: ['검색', '예비군수석'], | ||
comment: '개발이 제일 쉽다', | ||
}, | ||
]; |
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.
constants파일을 따로 만든 것은 정말 좋은 시도였던거 같습니다! 상수파일을 사용하면 코드 유지 보수성과 가독성을 크게 향상시킬 수 있는데 상수를 효과적으로 관리하고 응용프로그램이 확장될 때 업데이트 및 수정하기 쉽도록 할 수 있습니다! 타입스크립트에서는 특히 중요하죠!
export default function getAccentColorFromLocalStorage() { | ||
// local 저장소에서 key값이 accentColor를 가져옴 | ||
const accentColor = localStorage.getItem('accentColor'); | ||
// accentColor라는 값이 있다면 해당 값을 json parsing해서 변수에 저장하여 return 없으면 #87e4ac색 return | ||
return accentColor ? JSON.parse(accentColor) : '#87e4ac'; | ||
} |
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.
의미있게 아키텍쳐를 짠 보람이 있는거 같네요! 커스텀훅과 모듈화된 함수를 의미있게 분리하고 각각의 역할대로 잘 import해서
쓰게 하는 것이 굉장히 클린한 코드처럼 보입니다
export interface MontlyExpensesType { | ||
[key: string]: DailyExpensesType[]; | ||
} | ||
export interface DailyExpensesType { | ||
_id: string; | ||
amount: number; | ||
userId: string; | ||
category: string; | ||
date: string; | ||
__v: number; | ||
} |
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.
타입스크립트의 핵심 기능 중 하나가 Type-checking인데 지금처럼 컴포넌트 내부에 지정해주거나 공통으로 쓰이는 interface의 경우엔 이렇게 따로 파일을 만들어 관리해주는 것이 베스트인거 같습니다
expense.ts / seacrh.ts로 어떤 종류의 interface가 선언되었는지 확실히 명명해줌으로써 좋은 개발을 하는데 도움이 될거 같네요!
const dailyExpenses = useMemo(() => { | ||
if (monthlyExpenses && monthlyExpenses[day]) { | ||
return monthlyExpenses[day].map((expense) => ({ | ||
// 기존 객체를 다 가져오고 | ||
...expense, | ||
|
||
// 필요한 속성을 삽입 | ||
key: expense._id, | ||
time: formatDateAndTime(expense.date).time, | ||
})); | ||
} | ||
return []; | ||
}, [day, monthlyExpenses]); |
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.
메모이제이션을 잘 하는 것이 현업에서의 프론트엔드 개발자의 역량중 중요한 부분이 될텐데
useMemo를 적절히 활용하셨네요
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.
useCallBack과 useMemo의 차이점은 무엇일까요?
import { AccentColorContext } from '@/context/AccentColorContext'; | ||
import { useContext } from 'react'; | ||
|
||
export const useAccentColor = () => { | ||
const accentColorContext = useContext(AccentColorContext); | ||
|
||
// accentColorContext가 undefined인 경우 === wrapping을 벗어난 곳에서 사용하는 경우 | ||
if (!accentColorContext) { | ||
throw new Error('래핑 잘해라'); | ||
} | ||
const { accentColor, handleAccentColor } = accentColorContext; | ||
|
||
return { accentColor, handleAccentColor }; | ||
}; |
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.
context api를 사용하여 강조색을 전역관리 하는 건 거의 본적이 없는데
커스텀훅으로 따로 만들어서 매우 유용하게 사용하신 것이 인상이 깊었습니다
styled-components를 안 썼을땐 이런 방법도 좋을거 같네요!
.react-calendar { | ||
width: 80vw; | ||
max-width: 1200px; | ||
background: white; | ||
font-family: Arial, Helvetica, sans-serif; | ||
line-height: 1.125em; | ||
position:absolute; | ||
top:10%; | ||
border-radius: 15px 15px 0 0; | ||
} | ||
|
||
.react-calendar--doubleView { | ||
width: 700px; | ||
} | ||
|
||
.react-calendar--doubleView .react-calendar__viewContainer { | ||
display: flex; | ||
margin: -0.5em; | ||
} | ||
|
||
.react-calendar--doubleView .react-calendar__viewContainer > * { | ||
width: 50%; | ||
margin: 0.5em; | ||
} | ||
|
||
.react-calendar, | ||
.react-calendar *, | ||
.react-calendar *:before, | ||
.react-calendar *:after { | ||
-moz-box-sizing: border-box; | ||
-webkit-box-sizing: border-box; | ||
box-sizing: border-box; | ||
} | ||
|
||
.react-calendar button { | ||
margin: 0; | ||
border: 0; | ||
outline: none; | ||
} | ||
|
||
.react-calendar button:enabled:hover { | ||
cursor: pointer; | ||
} | ||
|
||
.react-calendar__navigation { | ||
display: flex; | ||
height: 60px; | ||
} | ||
.react-calendar__navigation__arrow{ | ||
width:60px; | ||
font-size:45px; | ||
padding-bottom:5px; | ||
} | ||
|
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.
class 네이밍 컨벤션부터 vw, em을 쓰는 디테일까지 깔끔한 스타일링 실력이 돋보입니다!
const handleDelete = async () => { | ||
await new Promise((resolve) => setTimeout(resolve, 500)); // 억지 0.5초 | ||
try { | ||
const response = await fetch( | ||
`${API_BASE_URL}/api/expenses/${selectedData?._id}`, | ||
{ method: 'DELETE', headers: { 'content-type': 'application/json' } }, | ||
); | ||
if (!response.ok) { | ||
console.log('서버로 부터 응답이 왔는데 에러임.'); | ||
message.error('오류가 발생하였습니다'); | ||
return; | ||
} | ||
// 삭제 성공 | ||
message.success('소비기록 삭제 완료'); | ||
setToggleFetch((prev) => !prev); | ||
} catch (error) { | ||
console.log('서버로 부터 응답 안옴', error); | ||
message.error('오류가 발생하였습니다'); | ||
} | ||
}; |
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.
비동기를 다루는 것이 프론트엔드 개발자에게 가장 중요한 능력중에 하나라고 생각하는데
async await promise 연산자를 사용하셨는데
억지라고는 주석에 들어가있지만
아마도 네트워크 통신이나 파일 읽어오는 시간에 대해 고민하고 쓰신 것 같습니다!
풀리퀘가 closed 되어서 다시 제출합니다.
KDT5-M6 가계부 토이 팀프로젝트
프로젝트 소개 💵
SOBI
는 소비내역이 달력에 표시되며 월별 소비금액을 그래프로 볼 수 있는 웹 어플리케이션입니다.SOBI 보러가기
로컬에서 테스트 하실 경우
root 폴더에 .env 파일 생성 후
숫자 바꾸면 다른 조 데이터도 볼 수 있어요문과이과 팀 소개
이
정우이
시우문
현수문
대현차트
소비내역 수정
소비내역 삭제
달력
검색 자동완성
API
Request:
Response:
Request:
Response:
Status: 200 OK
Request:
Response:
Request:
Response:
Request:
Response:
Request:
Response:
Request:
Response:
사용한 기술, 라이브러리
Environment
Config
Development
화면 구성
SOBI 웹페이지 tour
메인 화면
소비내역 등록 모달
서랍 메뉴
강조색 선택
소비 통계 페이지
고찰
이정우
협업
깃허브 이슈기능 활용
commit 단위 및 메세지
Ant Design
ChartJS
Context API
SPA에서 server state와 client state 동기화 문제
소비내역을 등록, 수정, 삭제가 발생할 때마다 서버로부터 최신의 데이터를 받아와야 함.
본 프로젝트에서는 togglefetch라는 변수를 useState로 선언하고 소비내역의 변경이 발생하는 handling 함수에서
setToggleFetch((prev) => !prev)
. 그리고 통신이 일어나는 useEffect의 dependency에 togglefetch를 넣어주었다.이 방법은 페이지전환이 발생하지 않는 SPA에서 server state와 client state 동기화 문제를 가장 쉽게(
새로고침) 해결할 수 있는 방법이다.다른 방법으로 get 요청 없이 client state를 setState로 업데이트 시켜주는 방법이 있다.
setState((prev) => [...prev, newData])
를 통해 화면을 재랜더링.또 다른 방법으로
react-query
라이브러리를 사용하는 방법이 있다.UTC시간, local 시간 문제
ISO 8601
이다.2023-07-22T17:51:36.506Z
와 같이 표기가 되며 z는 UTC를 의미함.UTC
...()을 하여 UTC시간(9시간 더해진 UTC시간)을 변환 없이 그대로 사용한다.이시우
문현수
문대현