Skip to content

[2주차] 이승연 과제 제출합니다.#1

Open
a-00-a wants to merge 20 commits intoCEOS-Developers:masterfrom
a-00-a:a-00-a
Open

[2주차] 이승연 과제 제출합니다.#1
a-00-a wants to merge 20 commits intoCEOS-Developers:masterfrom
a-00-a:a-00-a

Conversation

@a-00-a
Copy link
Copy Markdown

@a-00-a a-00-a commented Mar 17, 2026

배포링크: https://ceos-week2-react-todo-23rd-five.vercel.app/

느낀점

: 이번 과제를 진행하면서 프로젝트를 먼저 완성한 뒤, 다시 처음으로 돌아가 기능 단위로 커밋을 나누어 진행했습니다.

2주차까지는 개인 과제였지만, 앞으로 진행될 협업 과제에서는 단순한 기록이 아닌 진행 상황을 공유하기 위한 커밋이 중요하다는 점을 느끼게 되었습니다.

또한 커밋을 기능 단위로 나누는 것이 프로젝트 흐름을 이해하는 데에도 도움이 된다고 느꼈습니다.

Review Questions

- Virtual-DOM은 무엇이고, 이를 사용함으로서 얻는 이점은 무엇인가요?

: Virtual DOM은 실제 DOM을 직접 조작하지 않고, 메모리 상에 가상의 DOM을 만들어 변경된 부분만 실제 DOM에 반영하는 방식입니다.

예를 들어 Todo 하나의 상태가 변경되었을 때, 전체를 다시 렌더링하는 것이 아니라 변경된 TodoItem만 업데이트됩니다.

이를 통해 불필요한 DOM 조작을 줄일 수 있어 성능이 개선되고, 상태 기반으로 UI를 관리할 수 있어 코드 작성도 더 편해집니다.

- React.memo(), useMemo(), useCallback() 함수로 진행할 수 있는 리액트 렌더링 최적화에 대해 설명해주세요. 다른 방식이 있다면 이에 대한 소개도 좋습니다.

: React에서는 불필요한 렌더링을 줄이기 위해 다양한 최적화 방법을 제공합니다.

  • React.memo는 props가 변경되지 않으면 컴포넌트의 재렌더링을 막아줍니다.
  • useMemo는 계산 비용이 있는 값을 메모이제이션하여 불필요한 재계산을 방지합니다.
  • useCallback은 함수를 메모이제이션하여, 자식 컴포넌트에 전달될 때 불필요하게 새로 생성되지 않도록 합니다.

이 외에도 상태를 최소한으로 나누거나, 컴포넌트를 적절히 분리하는 것도 렌더링 최적화에 도움이 됩니다.

- React 컴포넌트 생명주기에 대해서 설명해주세요

: React 컴포넌트는 크게 Mount, Update, Unmount 단계로 나눌 수 있습니다.

  • Mount: 컴포넌트가 처음 생성될 때
  • Update: 상태나 props가 변경되어 다시 렌더링될 때
  • Unmount: 컴포넌트가 화면에서 제거될 때

함수형 컴포넌트에서는 useEffect를 사용하여 이러한 생명주기 흐름을 관리할 수 있습니다.
예를 들어, 특정 값이 변경될 때 localStorage를 업데이트하거나, 초기 렌더링 시 데이터를 불러오는 등의 작업을 수행할 수 있습니다.

};

const activeCount = useMemo(() => todos.filter((todo) => !todo.completed).length, [todos]);
const doneCount = useMemo(() => todos.filter((todo) => todo.completed).length, [todos]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

activeCount와 doneCount에서 useMemo가 각각 사용되고 있는데, 같은 todos를 순회하기 때문에 하나로 합치는 게 효율적으로 보여요!


useEffect(() => {
localStorage.setItem(currentDate, JSON.stringify(todos));
}, [todos, currentDate]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

currentDate가 변경될 때 localStorage.setItem Effect([todos, currentDate])도 함께 트리거되는데, 이 시점에서 todos의 값이 아직 업데이트되기 전이에요! useRefcurrentDate를 추적하고 setItem effect의 의존성에서 currentDate를 제거하면 더 안전할 것 같아요!!

useState의 비동기성
useState 대신 useRef를 써야하는 이유

Copy link
Copy Markdown
Member

@chaeyoungwon chaeyoungwon left a comment

Choose a reason for hiding this comment

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

시간이 부족하셨을 텐데도 과제를 성실히 제출해주셔서 감사합니다 !!
추가로 개선해보시면 좋을 부분들에 대해 코멘트 드렸습니다 🙇‍♀️🤩

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

리드미도 작성하셨네요 ㅎㅎ 아주 좋습니다 -!!
추후 과제에서도 작성하신다면, 파일 구조도 함께 정리해주시면 더 좋을 것 같아요 😊

https://dawonny.tistory.com/450

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

코드 전반적으로 hex 색상값을 직접 사용하는 부분이 보이는데, 기존 CSS에서 전역 색상 변수를 사용하신 것처럼
Tailwind에서도 theme 레이어에 --color-* 형태로 색상 토큰을 정의해보셔도 좋을 것 같습니다!

https://tailwindcss.com/docs/theme

Comment on lines +3 to +10
type TodoItemProps = {
todo: Todo;
index: number;
setDragIndex: (index: number) => void;
handleDrop: (index: number) => void;
onRemoveTodo: (id: string) => void;
onToggleTodo: (id: string) => void;
};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

컴포넌트 props는 type으로도 정의할 수 있지만, interface로도 작성이 가능합니다!
두 방식에는 각각 차이가 있으니, 한 번 비교해보시고 상황에 맞게 어떻게 정의할지 고민해보셔도 좋을 것 같아요 !!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

현재는 프로젝트 규모가 작아 App.tsx에 로직을 함께 작성하신 것 같은데요,
앞으로는 유틸 함수와 훅을 분리하여 구조화하는 방식도 고려해보셔도 좋을 것 같아요!
(ex: 날짜 관련 유틸은 utils/dateUtils.ts에 작성 후 export하여 사용)

Comment on lines +1 to +3
@import 'tailwindcss';
@custom-variant dark (&:where(.dark, .dark *));
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@import must precede all other statements (besides @charset or empty @layer)

현재 로컬에서 실행 시 해당 오류가 발생하고 있어요!
pretendard import 문을 파일 최상단에 위치하도록 수정해주시면 해결됩니다 🙂

useEffect(() => {
const savedDarkMode = JSON.parse(localStorage.getItem('darkMode') || 'false') as boolean;
setDarkMode(savedDarkMode);
}, []);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

38번줄의 setTodo47번줄의 setDarkMode에서

Error: Calling setState synchronously within an effect can trigger cascading renders

다음과 같은 오류가 발생하는 것을 확인하실 수 있습니다.
해당 오류는 반드시 수정해야 하는 것은 아니며, 이 오류가 발생한다고 해서 코드가 무조건 잘못된 것은 아닙니다!

다만, 상태 변경 → useEffect 실행 → 다시 상태 변경과 같은 흐름으로 이어질 경우 무한 루프가 발생할 수 있는 구조이기 때문에, 관련 공식 문서나 블로그 글을 한 번 참고해보시면 좋을 것 같습니다!

https://ko.react.dev/learn/you-might-not-need-an-effect
https://velog.io/@soyeon364/React-useEffectEvent

</button>

<button
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

버튼 요소에는 cursor-pointer를 적용해주시는 걸 추천드립니다!
모든 버튼에 한 번에 적용하고 싶으시면 index.css에서 button에 스타일로 넣어주셔도 좋아요!

Comment on lines +11 to +16
<aside
data-sidebar
className={`fixed left-0 top-0 z-50 flex h-full w-64 flex-col bg-[#fbf0d6] px-2 py-3 shadow-xl transition-transform duration-300 dark:bg-white ${
isOpen ? 'translate-x-0' : '-translate-x-full'
}`}
>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

앞으로 Tailwind CSS를 사용하다 보면 조건부 스타일링을 적용해야 하는 경우가 많을 텐데요,
clsx나 cn과 같은 3주차 세션 자료에 있는 유틸들을 다음 과제에서 한 번 적용해보시면 좋을 것 같습니다 -!!

Comment on lines +22 to +26
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggleTodo(todo.id)}
className="h-[18px] w-[18px] shrink-0 cursor-pointer appearance-none rounded-[5px] border-2 border-[#f9f9f9] bg-[#f9f9f9] transition-all checked:relative checked:bg-[#f9f9f9] checked:after:absolute checked:after:left-[3px] checked:after:top-[-2px] checked:after:text-sm checked:after:text-[#ff4d4d] checked:after:content-['✓']"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

현재 체크 표시를 top, left 위치 값으로 하드코딩하여 정렬하고 있어 중앙에서 약간 어긋나 보이는 것 같아요!
flex를 활용해 중앙 정렬하는 방식으로 구현해보셔도 좋을 것 같습니당

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

현재 사용되지 않는 이미지 파일들이 다수 포함되어 있는 것으로 보입니다.
추후 사용 계획이 없다면, 불필요한 파일은 정리해보시는 것을 추천드립니다!

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.

3 participants