[2주차] 김철흥 미션 제출합니다.#3
Conversation
seoyeon5117
left a comment
There was a problem hiding this comment.
캘린더도 직접 구현하시고 타입스크립트로 과제 하시느라 수고하셨습니다! 디자인도 열심히 구상하신 것 같아요 2주차 과제 고생 많으셨습니다!
| import leftArrow from '@/assets/left-arrow.svg?react'; | ||
| import rightArrow from '@/assets/right-arrow.svg?react'; | ||
|
|
||
| export const LeftArrowIcon = styled(leftArrow)` | ||
| width: 1.8rem; | ||
| height: fit-content; | ||
| `; | ||
|
|
||
| export const RightArrowIcon = styled(rightArrow)` | ||
| width: 1.8rem; | ||
| height: fit-content; | ||
| `; |
There was a problem hiding this comment.
왼쪽 화살표와 오른쪽 화살표에 두 개의 이미지를 사용하는 것보다 rotate(180deg)를 해서 하나의 이미지만 사용해도 좋을 것 같습니다!
| <S.DayListSection> | ||
| <S.DayList> | ||
| {DAY_LIST.map((day, index) => ( | ||
| <S.DayListItem key={index}>{day}</S.DayListItem> |
There was a problem hiding this comment.
key에 index값을 넣는 것은 권장되지 않습니다. 아래 문서 참고하시면 좋을 것 같아요!
| e.preventDefault(); | ||
|
|
||
| if (task.trim() === '') { | ||
| alert('할 일을 입력해주세요!'); |
There was a problem hiding this comment.
alert는 확인 버튼을 누르기 전까지 사용자의 다른 입력을 막아 사용성을 저해하기 때문에 modal을 사용하는 것을 추천드립니다!
| <Postit paperColor="#DDEBF1"> | ||
| <S.DoneHeader> | ||
| <S.DoneTitleSection> | ||
| <S.DoneTitle>Done</S.DoneTitle> | ||
| <DoneIcon /> | ||
| </S.DoneTitleSection> | ||
| <TaskCount taskCount={doneList.length} isDone={true} /> | ||
| </S.DoneHeader> | ||
|
|
||
| <TaskList tasks={doneList} /> | ||
| </Postit> |
| <S.TaskEditInput | ||
| type="text" | ||
| value={editedContent} | ||
| onChange={handleContentChange} | ||
| $isEditing={isEditing} | ||
| autoFocus | ||
| /> |
| @media (max-width: 1440px) { | ||
| align-items: center; | ||
| } | ||
|
|
||
| @media (max-width: 1024px) { | ||
| flex-direction: column; | ||
| padding: 6rem 3.2rem; | ||
| } |
| const Postit = ({ children, paperColor }: PostItProps): JSX.Element => { | ||
| return ( | ||
| <S.PostitWrapper> | ||
| <PostitPaper $paperColor={paperColor} /> |
There was a problem hiding this comment.
이미지가 깨질때나 스크린 리더를 사용하는 사용자를 고려하여 이미지 태그 사용하실 때는 alt 속성을 추가하는 것이 좋습니다!
https://www.tcpschool.com/html-tag-attrs/img-alt
BeanMouse
left a comment
There was a problem hiding this comment.
캘린더가 디자인 적이에요 이걸 직접 구현하셧다니 엄지 두개 드릴게요 👍👍
저랑 코드 스타일이 엄청 다른거 같아서 훨씬 배울점이 많은 것 같아요!!
| import { generateCalendar } from '@/utils/generateCalender'; | ||
| import { formatDate } from '@/utils/formatDate'; | ||
|
|
||
| import * as S from './Calendar.styled'; |
There was a problem hiding this comment.
이렇게 스타일 구현할 수 있다는 걸 처음 알았습니다... 신기하네용
| year: new Date().getFullYear(), | ||
| month: new Date().getMonth() + 1, | ||
| day: new Date().getDate(), |
There was a problem hiding this comment.
Date 객체를 새로 계속 생성하기보다 어디에 today 값을 설정해서 한번만 불러오는게 어떨까용?
| const handleDaySelect = (day: string) => { | ||
| setSelectedDate(day); | ||
| }; |
There was a problem hiding this comment.
이 정도의 함수는 onClick 안에서 처리할 수 있으면 좋을 것 같습니당
onClick={()=>setSelectedDate(day.FullDate)} 이런 느낌??
| const handleEditClick = () => { | ||
| setIsEditing(true); | ||
| }; | ||
|
|
||
| const handleCancelClick = () => { | ||
| setIsEditing(false); | ||
| }; |
There was a problem hiding this comment.
마찬가지로 함수를 따로 빼는 것 보다 인라인으로 적는게 코드 수나 가독성 쪽에서 좋을 것 같습니당
=> 함수가 여러번 재사용 되거나 useMemo, CallBack등을 사용해야할 때는 따로 빼는 것이 좋습니다!
| undefined | ||
| ); | ||
|
|
||
| export const useTasks = () => { |
There was a problem hiding this comment.
개인적으로 Context를 쓰는 부분은 파일명이나 함수명을 useTaskContext로 써봐도 좋을 것 같아요
| const selectedDateTask = useMemo( | ||
| () => tasksByDate[selectedDate] ?? [], | ||
| [tasksByDate, selectedDate] | ||
| ); | ||
|
|
||
| const toDoList = useMemo( | ||
| () => selectedDateTask.filter((task) => !task.completed), | ||
| [selectedDateTask] | ||
| ); | ||
| const doneList = useMemo( | ||
| () => selectedDateTask.filter((task) => task.completed), | ||
| [selectedDateTask] | ||
| ); |
There was a problem hiding this comment.
이정도의 계산은 그냥 일반 변수로 해도 될 것 같다는 생각이 있습니당
오히려 불필요한 메모지에이션으로 복잡성만 늘릴 수도 있어요

🔗 Deploy URL
To Do List
🫥 느낀 점
🤷🏼♂️
KQ 1. Virtual-DOM과 사용시의 이점
Virtual-DOM 이란?
실제 DOM(Document Object Model)을 바로 업데이트하지 않고 메모리에 가상으로 DOM 트리를 생성하여 관리하는 DOM 형식
사용 시의 이점
KQ 2.
React.memo(),useMemo(),useCallback()함수로 진행할 수 있는 렌더링 최적화✅ React.memo()
함수형 컴포넌트를 memoization(메모이제이션)하여, props가 변경되지 않으면 재렌더링하지 않음
일반적인 PureComponent의 함수형 컴포넌트 버전이라고 볼 수 있음
컴포넌트가 불필요하게 렌더링되지 않아 성능이 좋아집니디만, props가 많거나 복잡한 경우에 주의 깊게 사용해야 합니다.
✅ useMemo()
값(value)을 메모이제이션하기 위한 Hook으로, 특정 값이 변경될 때만 값이 다시 계산됨
연산 비용이 큰 값이나 객체가 불필요하게 재생성되지 않도록 하여 성능을 최적화할 수 있음
✅ useCallback()
함수를 메모이제이션하기 위한 Hook으로, 특정 의존성 배열(dependency array)의 값이 변경되지 않으면 이전에 저장된 동일한 함수 인스턴스를 반환함
📌 자식 컴포넌트에 콜백 함수를 전달할 때 불필요한 재렌더링을 방지하는데 특히 유용함
KQ 3. React 컴포넌트 생명주기
React 컴포넌트는 생성 → 업데이트 → 소멸 단계를 거침
1. 컴포넌트 마운트(Mount)
: 컴포넌트가 처음 화면에 나타날 때 실행
빈 배열 []을 의존성 배열로 넘기면 처음 한 번만 실행됨
ex.) API 요청, 이벤트 리스너 등록
2. 컴포넌트 업데이트(Update)
: 상태(state)나 props가 변경될 때마다 실행됨
someValue가 바뀔 때만 실행됨(여러 상태를 넣으면 각각의 변화에 따라 실행됨)
3. 컴포넌트 언마운트(Unmount)
: 컴포넌트가 사라질 때(clean-up) 실행
주로 타이머 제거, 이벤트 리스너 해제, 구독 해제 등에 사용
🔁 전체 구조 예시