Skip to content

Conversation

Tutankhannun
Copy link

@Tutankhannun Tutankhannun commented Sep 20, 2025

배포링크

배포화면
image

Review Question

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

-> 실제 DOM을 직접 건드리기 전에, 자바스크립트 객체로 된 “가상 트리”를 메모리에서 먼저 만들고 변화를 계산해 최소한의 실제 DOM 조작만 반영하는 기법이다.
-실제 DOM에는 브라우저가 화면을 그리는데 필요한 모든 정보가 들어있어 실제 DOM을 조작하는 작업이 무겁기 때문에 사용한다.
image
DOM의 상태를 메모리에 저장-> 변경 전과 변경 후의 상태를 비교 -> 최소한의 내용만 반영

이러한 과정을 통해 성능 향상을 이끌어낸다. DOM의 상태를 메모리 위에 계속 올려두고, DOM에 변경 있을 경우 해당 변경 사항만 반영하는 것이다.

2. React.memo(), useMemo(), useCallback() 함수로 진행할 수 있는 리액트 렌더링 최적화에 대해 설명해주세요.

(1) React.memo()

  • 컴포넌트 전체를 메모이제이션하여 React.memo() 사용 시 최적화 된 컴포넌트(메모이제이션 된 컴포넌트)를 반환해준다.
  • props가 바뀌지 않았다면, 이전 렌더링 결과를 재사용하고 리렌더링을 건너뛴다.

(2) useMemo()

  • 값(value) 계산을 메모이제이션한다.
  • 같은 값을 사용할 것이라면 결과 값을 캐싱해놓고 이 캐싱된 값을 사용하여 효율을 높인다.

(3) useCallback()

  • 함수(function)를 메모이제이션한다.
  • 함수를 props로 전달하는 경우 특정 함수를 새로 생성하지 않고 재사용할 수 있도록 한다.

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

-> 컴포넌트가 생성되고 사용되고 소멸될 때 까지 일련의 과정을 말한다.
-클래스형 컴포넌트에서는 메서드로, 함수형 컴포넌트에서는 훅(Hook)으로 다룬다.

-마운팅(mounting) 이벤트: 엘리먼트를 DOM 노드에 추가할 때 발생하며, 한 번만 실행된다.
-갱신(updating) 이벤트: 속성이나 상태가 변경되어 엘리먼트를 업데이트할 때 발생하며, 여러 번 실행된다.
-언마운팅(unmounting) 이벤트: 엘리먼트를 DOM에서 제거할 때 발생하며, 한 번만 실행된다.
-Error: 에러 발생 시 한 번만 실행한다. 최상위 컴포넌트에 한 번만 작성하며 에러 발생 시 행동을 정한다.

(1) 클래스형 컴포넌트 (메서드 기반)
각 단계에서 componentDidMount(), componentDidUpdate(), componentWillUnmount() 같은 메서드를 사용한다.

(2) 함수형 컴포넌트 (Hook 기반)
각 단계를 각각의 메서드로 구현하지 않고 useEffect 훅이 이 역할을 통합해서 수행한다.

어려웠던 점

(1) 프로젝트 초기 세팅
npm init, vite 실행, package.json 관리 등 바닐라 JS 때는 없던 설정 과정이 낯설었음.
npm run dev, npm run build 같은 명령어의 의미와 흐름을 이해하는 데 시간이 필요했음.

(2)파일 관리의 복잡함
바닐라 프로젝트는 index.html + style.css + script.js 정도로 단순했는데,
React는 App.tsx, TodoList.tsx, TodoItem.tsx 등 컴포넌트 단위로 나눠 관리하다 보니 구조를 잡는 게 어려웠음.

(3)에러 메시지 이해
리액트도 사용해보지 못한 상황에서 타입스크립트를 쓰니 에러 메시지를 이해하는 데 어려웠음
'React' is declared but its value is never read 같은 타입스크립트/ESLint 경고가 처음엔 당황스러웠음.
에러 해결 과정에서 린트/타입 검사 도구의 역할을 배울 수 있었지만 진입장벽이 느껴졌음.

배운 점

(1)컴포넌트 기반 개발
리액트를 사용하는 큰 특징 중 하나로 알고있던 컴포넌트 기반 개발이라는 것이 무엇인지 조금 알게됨.
UI를 작은 단위(TodoItem, TodoList)로 쪼개서 재사용할 수 있어, 규모가 커질수록 관리가 쉬워질 것 같음.

(2)Virtual DOM과 효율성
실제 DOM 조작을 일일이 신경 쓰지 않고, 상태만 선언적으로 바꿔주면 React가 알아서 최소한의 DOM 변경을 수행하는 점이 인상 깊었음.

(3)개발 환경/도구 이해
ESLint, 타입스크립트, 빌드 도구 등을 접하며, 바닐라보다 체계적인 환경에서 개발이 진행된다는 점을 알게 됨.

@Wannys26
Copy link

지금 Files Changed에 들어가면 node_modules 폴더만 뜨는거 같습니다..ㅜ 포크하신 레포지토리 가보니까 src 폴더 있던데 다시 PR 올려주실 수 있으신가요??

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.

안녕하세요, 윤성 님! 2주차 과제 하시느라 수고 많으셨습니다👍 몇 가지 의견을 남겨 보았으니 참고해 보시면 좋을 것 같습니다!
+주완 님이 남겨주신 것처럼 지금 node_modules가 전부 업로드 되어 있는 상황이라 추후 진행될 과제에서는 이 부분도 꼭 확인해 보셔야 할 것 같습니당

Choose a reason for hiding this comment

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

favicon이 기본 상태로 남아 있는 것 같은데 이것도 바꿔 보면 좋을 것 같습니당

import styled from 'styled-components'
import { formatKoreanLabel } from '../utils/date'

const Bar = styled.div`

Choose a reason for hiding this comment

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

component 안에서도 style은 따로 파일을 분리해서 나눠보면 가독성이 좋아질 것 같아요! 주완 님께서 그런 방식으로 코드를 작성하셔서 참고해 보셔도 좋을 것 같습니당

}, [todos])

// 현재 날짜의 목록
const todays = useMemo(() => todos.filter((t) => t.due === currentDate), [todos, currentDate])

Choose a reason for hiding this comment

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

useMemo로 성능 최적화를 적용하셨네요!👍

setTodos((prev) => [
...prev,
{
id: `${Date.now()}${Math.random().toString(16).slice(2)}`,
Copy link

@only1Ksy only1Ksy Sep 21, 2025

Choose a reason for hiding this comment

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

이런 방법도 좋지만, uuid를 활용하면 충돌 걱정 없이 더욱 안전한 로직이 될 것 같습니다!
https://it-timehacker.tistory.com/317

}, [todos])

// 현재 날짜의 목록
const todays = useMemo(() => todos.filter((t) => t.due === currentDate), [todos, currentDate])

Choose a reason for hiding this comment

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

지금은 todos 객체를 하나의 배열 형태로 다루고, 날짜가 바뀔 때마다 매번 filter로 순회하고 있는데, localstorage에 저장할 때부터 { "2025-09-19": Todo[] } 와 같이 두면 필터링이 더 간단해질 수 있을 것 같네요!

Comment on lines +107 to +117
// 날짜 이동/선택
const goPrev = () => {
const d = new Date(currentDate + 'T00:00:00')
d.setDate(d.getDate() - 1)
setCurrentDate(toYYYYMMDD(d))
}
const goNext = () => {
const d = new Date(currentDate + 'T00:00:00')
d.setDate(d.getDate() + 1)
setCurrentDate(toYYYYMMDD(d))
}

Choose a reason for hiding this comment

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

지금 goPrev와 goNext가 -1, +1 숫자만 다르고 로직은 동일한 상황이니, 아래와 같이 중복을 줄이는 방향으로 바꾸는 방법도 있을 것 같네요!

Suggested change
// 날짜 이동/선택
const goPrev = () => {
const d = new Date(currentDate + 'T00:00:00')
d.setDate(d.getDate() - 1)
setCurrentDate(toYYYYMMDD(d))
}
const goNext = () => {
const d = new Date(currentDate + 'T00:00:00')
d.setDate(d.getDate() + 1)
setCurrentDate(toYYYYMMDD(d))
}
// 날짜 이동/선택
const changeDate = (offset: number) => {
const d = new Date(currentDate + 'T00:00:00')
d.setDate(d.getDate() + offset)
setCurrentDate(toYYYYMMDD(d))
}
const goPrev = () => changeDate(-1)
const goNext = () => changeDate(1)

import styled from 'styled-components'
import type { Todo } from '../types'

const Li = styled.li<{ done: boolean }>`

Choose a reason for hiding this comment

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

지금 전체적으로 styled-component와 classname 기반 스타일링이 혼용되어 있는 것 같아요! component 기반으로 쪼개서 styled component 방식으로 일관되게 통일하는 쪽이 더 좋지 않을까 싶습니당

@Wannys26
Copy link

Wannys26 commented Sep 21, 2025

2주차도 고생하셨습니다! 아직 node_modules가 있는 상태라, files changed 탭에서 리뷰를 작성하기엔 어려움이 있어, 여기에 하나하나 적도록 하겠습니다! 리뷰 읽어보시고 궁금하신 점 있으시면 댓글 달아주세요!

  1. 지금 폰트가 Pretendard가 적용이 안된거 같습니다!
    React 프로젝트에 Pretendard 웹폰트 적용

  2. 위에서 서연님이 언급하신 uuid를 활용해야되는 이유는 이 글을 참고하시면 더 이해가 잘 되실거에요!
    index를 key로 사용하면 안되는 이

  3. 그리고 할 일/완료된 일 개수가 떠야하는게 요건 중 하나였는데 누락된거 같습니다!

  4. 추가 버튼이 기본적으로 세로로 되어있는데, 버튼 스타일에
    white-space: nowrap; 이 코드 추가하시면 해결되실 겁니다!

그리고 밑에 사진처럼 할 일 input이 두 줄 이상 넘어가면 완료 버튼이 밀려나는데,
이 점도 고려하셔서 수정하시면 좋을거 같습니다!
image

  1. 스타일 작성해두신 것도
    컴포넌트명.Style.ts 이렇게 따로 분리하시는 것도 좋을 거 같습니다!
    21기 react-todo 중에 폴더 구조가 잘 되어있는게 많이 있으니 참고해보셔요!

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.

작성해주신 코드와 사이트 잘 봤습니다! 기능별로 컴포넌트를 분리하여 작성하셔서 더 가독성이 좋았던 것 같습니다😄

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.

styled-components를 활용하는 경우, 기존 Vanilla CSS가 남아있거나 외부 라이브러리에서 className으로만 꼭 참조해야하는 경우가 아닌 이상 유지보수와 일관성을 위해 제거해주시는 것이 가독성 면에서도 좋을 것 같습니다!

<button type='button' aria-label='달력 열기' onClick={openPicker}>
📅
</button>
<input ref={dateInputRef} type='date' className='visually-hidden' />
Copy link

@Jy000n Jy000n Sep 22, 2025

Choose a reason for hiding this comment

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

아래와 같이 onChange 핸들러를 사용해서 인풋 태그에 바로 연결하는 방식을 사용하면 위 useEffect(57~65줄)에 이벤트들을 직접 바인딩할 필요 없이 더 간단한 코드가 될 것 같습니다 !
<input ref={dateInputRef} type='date' className='visually-hidden' onChange={(e) => onPick(e.target.value)} />

Copy link

Choose a reason for hiding this comment

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

styled-components의 DefaultTheme를 프로젝트에서 정의한 Theme 타입으로 확장한 부분이 인상적이네요😊 새로운 방법 알게 되었습니다!

<span className='title'>{todo.text}</span>
<div className='actions'>
<label style={{ marginRight: 8 }}>
<input type='checkbox' checked={todo.done} onChange={onToggle} data-action='toggle' />
Copy link

Choose a reason for hiding this comment

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

개인적으로 checkbox의 사이즈가 조금 더 컸어도 괜찮을 것 같습니다!
그리고 다른 버튼들처럼 cursor:pointer;도 적용해주시면 좋을 것 같아요

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