Skip to content

Conversation

@dragunshin
Copy link

@dragunshin dragunshin commented Sep 20, 2025

배포 링크

image

느낀점

우선 리액트의 기본적인 개념을 공부하고, 프로젝트를 진행하느라 시간이 많이 부족했다. 리액트를 하면서 객체형 프로그래밍과 유사한 것 같아 신기했다.
html css js 보다 리액트가 더 나은 점은 컴포넌트로 관리하면서 문제점을 쉽게 찾고 기능별로 나누어 코딩이 가능하다는 점이라고 생각한다
다음 프로젝트부터 리액트의 장점을 더 활용할 수 있도록 배우고 적용해보고 싶다!

REVIEW QUESTION

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

Virtual-DOM은 실제 DOM의 가벼운 복사본으로 메모리 상에 존재하며,Javascript 객체 형태로 존재한다
실제 DOM을 직접 조작하는 대신 간접적으로 조작하면서 렌더링 성능을 향상시키는 역할을 한다
웹 페이지의 DOM 구조를 메모리에 로드하여, 실제 DOM에 변화를 주기 전에 먼저 변화를 처리한다. 실제 DOM에 접근하는 것보다 성능적으로 효율적이다
Virtual DOM과 비교해서 실제로 변경이 필요한 부분만 찾아내 실제 DOM에 적용한다

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

React는 상태가 변경될 때마다 컴포넌트를 리렌더링한다.

React.memo()는 컴포넌트의 props가 변경되지 않았다면 리렌더링을 방지하여 성능을 최적한다. 함수형 컴포넌트를 React.memo()로 감싸면, React는 해당 컴포넌트를 렌더링하기 전에 이전 props와 현재 props를 비교하여, 같다면 메모리에 저장된 이전 렌더링 결과를 재사용한다.

useMemeo()는 memoized value를 반환하는 훅. 복잡한 연산의 결과를 저장하고, 배열의 값이 변경될 때만 해당 연산을 다시 실행한다.

useCallback()은 useMemo()와 유사하다. 함수를 메모이제이션한다.

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

React 컴포넌트는 생성되고, 업데이트되며, 소멸하는 일련의 과정을 가진다. 생명주기라고 하며, 각 단계에서 특정 메서드들이 호출된다. 클래스형 컴포넌트와 함수형 컴포넌트의 생명주기는 조금 다르게 표현된다.

함수형 컴포넌트에서는 Hooks를 사용하여 클래스형 컴포넌트의 생명주기 기능을 구현한다 useState() useEffect()가 대표적이다.

Choose a reason for hiding this comment

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

전체적으로 색감도 예쁘고 완료된 할 일과 그렇지 않은 할일을 분리하는 방식이 인상적입니다. 다만 리스트의 위치가 고정되어 있지 않아서 여러 할 일들을 지울 때 커서를 계속 움직여야 한다는 점이 좀 불편합니다. 위치를 고정하고 할 일이 추가 되면 스크롤을내리는 방식은 어떨까 싶습니다.

}
});

const todos = todosByDate[selectedDate] || [];

Choose a reason for hiding this comment

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

날짜에 투두가 없을때마다 매번 새로 빈 배열을 만드는 것인가요? 그렇다면 todos배열이 매번 달라지고 useMemo도 매번 다시 계산되니 app 밖에
const emptyTodos = todo[]: []; 를 두고
const todos = todosByDate[selectedDate] ?? emptyTodos;
이렇게 쓰면 빈 배열을 재사용할 수 있을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

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

이 부분은 생각못했던 부분인데 프로젝트가 커질수록 효율이 더 좋을 것 같네요 감사합니다

if(!date) return;
setTodosByDate((prev) => {
const current = prev[date] ?? [];
const next = update(current);

Choose a reason for hiding this comment

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

제가 프로그램을 사용하고 local session을 보니 투두를 추가했다가 모두 지운 뒤 다른 날짜로 이동해도 이전 날짜에 빈 배열 []을 저장하고 있었습니다. 예를 들어 9/22에 투두를 2개 추가했다가 모두 지우고 날짜를 10/22로 바꿔도 9/22에 불필요한 빈 배열이 저장되어 있습니다. 이 부분을 수정해서 리스트가 비었다면 local session에서도 지우는 편이 나을 것 같습니다

if(mode === 'done') return todos.filter((task) => task.done);
return todos;
}, [todos,mode]);

Choose a reason for hiding this comment

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

useMemo로 filtered와 todocount를 계산해 불필요한 리렌더를 줄인 점이 좋습니다.

Copy link
Member

@KWONDU KWONDU 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
Member

Choose a reason for hiding this comment

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

지금 prettier 세팅이 겹치는 거 같아요 (react-todo/.prettierrc)

Copy link
Member

Choose a reason for hiding this comment

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

다양한 prettier 속성이 있습니다. tab width 조절해주는 속성도 있고, semicolon 붙일지 말지 결정해주는 속성도 있고요. prettier가 결국 협업 시 충돌 방지를 위해 사용되는 라이브러리인 만큼 다양한 속성을 사용해보시면 좋을 거 같아요

"@vitejs/plugin-react": "^5.0.3",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
Copy link
Member

Choose a reason for hiding this comment

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

다양한 eslint plugin을 사용하는 습관은 좋은 것 같네요. 관련하여 import 순서 정렬해주는 plugin 등 다양한 종류가 있으니 더 찾아보시는 것도 추천드려요

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Todo</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/pretendard/dist/web/static/pretendard.css" />
Copy link
Member

Choose a reason for hiding this comment

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

package json 파일을 보면 pretendard 폰트를 패키지 형태로 다운받아서 사용하시는 거 같은데, 해당 부분은 중복되는 것 같습니다

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
Copy link
Member

Choose a reason for hiding this comment

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

상황에 맞게 메인 언어 변경하시는 걸 추천드려요. 검색 엔진 최적화 등 더욱 완성도 높은 결과물을 만들 수 있습니다

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
Copy link
Member

Choose a reason for hiding this comment

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

현재 코드로는 js/jsx 확장자만 감지가 됩니다. typescript를 사용하시는 만큼 ts, tsx도 추가해 주세요

Copy link
Member

Choose a reason for hiding this comment

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

구조별로 이렇게 파일을 분리하신 건 좋은 것 같습니다.

background: ${({ $active }) => ($active ? 'brown' : 'orange')};
color: ${({ $active }) => ($active ? '#fff' : '#111')};
cursor: pointer;
`;
Copy link
Member

Choose a reason for hiding this comment

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

button tag 특성상 많은 default css style이 내장되어 있습니다. 대표적으로는 webkit-tap-highlight-color property를 들 수 있을 것 같습니다 (버튼 클릭 시 파란색 테두리)

이를 해결하기 위해서 reset.css나 normalize.css 같이 정형화된 css 코드가 있는데요 이를 찾아보시면 좋을 것 같습니다

대표적으로 meyer's reset css가 있습니다

Copy link
Member

Choose a reason for hiding this comment

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

별개로 3주차 때 사용하실 tailwind CSS의 경우 ver4.0부터 기본적으로 reset css가 내장되어 있습니다

value={text}
onChange={(e) =>setText(e.target.value)}
onKeyDown={(e) => {
if(e.key === 'Enter' && !e.nativeEvent.isComposing) enter();
Copy link
Member

Choose a reason for hiding this comment

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

isComposing property 적용하신 것 좋은 거 같아요

Copy link
Member

Choose a reason for hiding this comment

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

3주차부터는 폴더 구조 및 파일 분리를 통한 컴포넌트화가 더욱 중요해질 시점입니다. 어떤 구조로 폴더를 분리할지, components 폴더를 예시로 들면 layout/header, layout/footer / task/input, task/item 이렇게 나눌지 input/task-input, input/common-md 이렇게 나눌지 등 고민해보시면 좋을 거 같아요

<>
<GlobalStyle />
<div style={{marginBottom:'20px', textAlign:'center'}}>
<input type='date' value={selectedDate} onChange={(e)=> setSelectedDate(e.target.value)} />
Copy link
Member

Choose a reason for hiding this comment

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

앞서서 header에는 cursor: pointer;를 적용하셨는데, 좀 더 UX를 고려하고자 하면 해당 input에도 동일한 속성을 적용하면 좋겠네요.

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