Skip to content

Conversation

Wannys26
Copy link

@Wannys26 Wannys26 commented Sep 19, 2025

배포 링크

CEOS Vanilla-todo


구현 화면

현재 날짜는 초록색 표시된 모습
image

할 일을 적을 수 있는 모달창이 띄워진 모습
image

할 일이 추가된 날짜는 노란색으로 표시되는 모습
image


느낀 점

2주차 과제 공부
과제 마감이 다가오면서 조금은 소홀하게 진행된 부분이 있었지만, 따로 공부하며 느낀 점과 추가 학습이 필요한 부분들을 정리해 노션 페이지에 기록해두었습니다.

손주완 과제 상세 분석
이번에 새로 알게 된 사이트인 Deepwiki를 활용해 보았습니다. 깃허브 레포지토리 주소만 입력하면 프로젝트를 자동으로 분석해주는데, 결과가 논문처럼 체계적으로 정리되어서 좋습니다.
(우클릭 후 “한국어로 번역” 기능을 사용하면 바로 한국어로 확인 가능합니다.) 다른 오픈소스들도 쉽게 분석할 수 있어 추천드립니다.

이번에도 관심사 분리 원칙을 기반으로 프로젝트를 구성했습니다. 다만, 개인적으로는 컴포넌트 단위로 폴더를 나누는 방식이 개발할 때 더 편리하지 않을까 생각했습니다. 리뷰어분들은 보통 어떤 기준으로 폴더 구조를 정하시는지 궁금합니다 ㅎㅎ

src/
├── components/           # Reusable UI components
├── contexts/            # React Context providers  
├── hooks/               # Custom React hooks
├── pages/               # Page-level components
├── styles/              # Global styles and theme
├── types/               # TypeScript type definitions
├── utils/               # Utility functions
└── App.tsx              # Application root component

그리고 1주차 리뷰 받았던 사항들인

  1. UUID 활용하기
  2. 날짜 변수 일치
  3. 모달 크기 및 반응형 디자인
  4. Prettier 사용
  5. todo/done 개수
    들도 추가 및 개선했습니다!

key 값으로 UUID를 사용하라는 리뷰가 많았는데, 왜 index를 쓰면 안 되는지 잘 이해하지 못했었습니다.
원채영님의 PR 리뷰에 달려있던 링크 글이 제일 잘 설명되어있던거 같아서 첨부합니다.

왜 react에서 index를 key로 사용하면 안되는 걸까?

아쉬운 점이 있다면 TodoModalContext.tsx가 너무 길게 작성되어있 점이라고 생각합니다.
ModalState를 관리하는 ModalContext와 Todo 데이터를 관리하는 TodoContext로 분리하는게 맞다고 생각이 듭니다.

이번에 MT도 있고 해서, 리뷰하시는 분들을 위해 계획해뒀던 사이드바 기능들은 일단 넣지 않았습니다.
이번 리뷰 끝나면 TodoModalContext 리팩토링 및 사이드바 기능들 추가하겠습니다.


Review Questions

1) Virtual DOM은 무엇이고, 이점은 무엇인가요?

  • Virtual DOM은 실제 DOM을 메모리에 가볍게 복사해둔 트리
    구조이다.
  • 상태가 바뀌면 리액트는 Virtual DOM을 먼저 수정하고, 이전 Virtual
    DOM과 비교(diff)하여 달라진 부분만 실제 DOM에 반영한다.

이점

  • 전체 DOM을 새로 수정하지 않아 성능이 향상된다.
  • 개발자는 상태 기반으로 UI를 선언만 하면 되므로 코드 작성이
    단순해진다.
  • 같은 개념을 웹뿐 아니라 모바일(React Native) 등 다양한 환경에서도
    활용할 수 있다.

2) React.memo / useMemo / useCallback으로 할 수 있는 최적화

  • React.memo: props가 변하지 않으면 컴포넌트의 재렌더링을
    방지한다.
  • useMemo: 계산 결과를 메모리에 저장하여 동일한 입력일 때 불필요한
    재계산을 피한다.
  • useCallback: 함수 정의를 메모리에 저장하여 매번 새로운 함수가
    생성되지 않도록 한다.

추가적인 방법

  • key는 index 대신 고유 id를 사용한다.
  • 상태는 꼭 필요한 범위에서만 관리하여 불필요한 리렌더링을 줄인다.
  • 코드 스플리팅, startTransition 등 리액트 최적화 기능을 활용한다.

3) React 컴포넌트 생명주기

  • 마운트(Mount): 컴포넌트가 처음 DOM에 추가되는 시점. 이때
    useEffect가 실행된다.
  • 업데이트(Update): props나 state가 변경될 때. 변경된 부분만 실제
    DOM에 반영된다.
  • 언마운트(Unmount): 컴포넌트가 DOM에서 제거되는 시점. cleanup
    함수가 실행된다.

Hook 차이

  • useEffect: DOM 업데이트 이후 비동기로 실행. 데이터 요청, 로그 출력
    등에 적합하다.
  • useLayoutEffect: DOM이 업데이트된 직후 동기로 실행. 레이아웃
    계산이나 스크롤 위치 조정에 적합하다.

Copy link

@only1Ksy only1Ksy left a comment

Choose a reason for hiding this comment

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

안녕하세요, 주완 님! 캘린더도 직접 구현하시고 1주차 리뷰도 반영해 주셨네요👍 deepwiki는 저도 처음 보는데 덕분에 신기한 거 알아갑니당 몇 가지 의견 남겨 보았으니 참고해 보시면 좋을 것 같습니다 2주차 과제도 수고 많으셨습니다~!!

+현재 vercel 배포가 private으로 설정되어 있는 것 같아 확인 한 번만 부탁드립니다!

@@ -0,0 +1,103 @@
import { useTodoModalContext } from '@/contexts/TodoModalContext';
import {

Choose a reason for hiding this comment

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

import * as S from '@/components/TodoModal/TodoModal.Styled'; 과 같이 사용하고, S.ModalOverlay와 같은 방식으로 불러오는 방식도 있을 것 같습니당 불러오는 컴포넌트가 많은 것 같아서요!

// 할 일 추가
const addTodo = () => {
const trimmedInput = todoInput.trim();
if (!trimmedInput || !modalState.selectedDate) return;

Choose a reason for hiding this comment

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

UX 향상을 위해 alert나 error UI 같이 왜 추가가 안 되는지 사용자가 알 수 있는 장치가 있으면 좋을 것 같아요!

<EmptyMessage>할 일이 없습니다.</EmptyMessage>
) : (
todos.map((todo) => (
<TodoItem key={todo.id} $completed={todo.completed}>

Choose a reason for hiding this comment

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

각 todo의 고유한 id 값으로 key를 설정해 주신 점 좋네요!👍


// Enter 키 핸들러
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {

Choose a reason for hiding this comment

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

enter를 이렇게만 처리할 시 한글 중복 입력이 발생할 수 있으니 isComposing 조건을 활용하시는 것을 추천드립니당 자윤 님께서 해당 사항을 잘 적용해 주셨네요!

Choose a reason for hiding this comment

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

현재 1. 모달 상태 관리, 2. 투두 데이터 관리, 3. getter 등 전부 한 context 안에 묶여 있는 것 같습니다! 모달 상태 관리와 투두 데이터 관리로 context를 분리하고, getter와 같이 단순 파생 데이터를 리턴하는 함수는 그냥 컴포넌트 단에서 활용하는 방법은 어떨까요?

Choose a reason for hiding this comment

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

useLocalStorage 커스텀 훅으로 useState처럼 활용하면서 localStorage 동기화를 깔끔하게 해주셨네용👍

darkGray: '#6c757d',
lightBlue: '#e3f2fd',
yellow: '#fff3cd',
yellowDark: '#ffeaa7',

Choose a reason for hiding this comment

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

사소하지만 일관성을 위해 위 color들과 동일한 순서로 네이밍해 주시면 좋을 것 같습니당!

Suggested change
yellowDark: '#ffeaa7',
darkYellow: '#ffeaa7',

year: number,
month: number,
isOtherMonth: boolean,
keyPrefix: string,

Choose a reason for hiding this comment

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

prev, current, next의 세 값만 쓰이니 타입을 좁혀주면 어떨까요??

Copy link

@Jy000n Jy000n left a comment

Choose a reason for hiding this comment

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

작성해주신 코드 잘 봤습니다:) 파일들을 세세하게 여러 컴포넌트별로 분리해둬서 보기에 더 좋았던 것 같아요! 다만, vercel 배포가 private으로 되어 있는 것 같아 사이트의 모달 같은 기능들을 확인해볼 수 없는게 아쉬웠습니다🥹


// Enter 키 핸들러
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
Copy link

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

스타일 코드들을 따로 분리해두니까 확실히 가독성 있네요 !!

type="text"
value={todoInput}
onChange={(e) => setTodoInput(e.target.value)}
onKeyPress={handleKeyPress}
Copy link

Choose a reason for hiding this comment

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

현재 해당 이벤트를 처리하는 데에는 문제가 없지만, onKeyPress 이벤트는 현재 deprecated되어서, MDN에서는 onKeyDown 이벤트를 권장하고 있습니다! 아래 관련 MDN 사이트 같이 첨부해드립니당
Keypress) https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event
Keydown) https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event

$isOtherMonth={isOtherMonth}
$isToday={todayCheck}
$hasTodos={hasTodos}
onClick={isOtherMonth ? () => {} : () => onDateClick(day)}
Copy link

Choose a reason for hiding this comment

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

아무 동작도 하지 않게끔 하는 코드를 불필요한 빈 함수(()=>{})를 생성하는 것보다는 undefined를 주거나 CSS로 시각적으로 표시해주는 방법을 사용하는 것이 불필요한 렌더링도 줄이고, 다른 사람들이 코드를 볼 때 이해도 더 쉬울 것 같습니다 !

Copy link

Choose a reason for hiding this comment

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

사용되지 않는 이미지는 지우셔도 될 것 같습니더

"styled-components": "^6.1.19",
"uuid": "^13.0.0"
},
"devDependencies": {

Choose a reason for hiding this comment

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

eslint와 prettier를 같이 사용할 때 기능이 겹치는 점이 있으면 충돌이 생길 수 도 있어 eslint-config-prettier를 설치해주면 방지할 수 있습니다. 아래 링크 참고해보시면 좋습니다~
eslint-config-prettier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants