Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2주차] 김동혁 미션 제출합니다. #1

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

ddhelop
Copy link
Member

@ddhelop ddhelop commented Mar 21, 2024

🔗 링크

https://react-todo-19th-dh-1.vercel.app/

📌 기능구현

  • 할 일 입력창(Form)에 텍스트를 입력하고 enter 혹은 버튼클릭으로 할 일 추가
  • 할 일 추가 / 삭제 시 애니메이션
  • 할 일 삭제
  • 할 일 완료 표시
  • localStorage에 할 일, 완료 상태 저장
  • 모바일 (768px 이하) 반응형 스타일
  • 할 일과 완료된 할 일 카운트

🤔 후기

전 과제와 비교해보기 위해 똑같은 인터페이스와 기능 React로 구현하는 것을 목표로 이번 2주차 과제를 해보았습니다.
html, css, javascript로 투두리스트를 구현하는 것보다 react 라이브러리를 이용해서 구현하는 것이 확실히 편리하다는 것을 느꼈습니다.
특히 useState나 useEffect같은 React Hook으로 상태관리 하는 것이 DOM을 조작하는 것보다 직관적이고 관리하기 용이하고,
StyledComponent로 스타일 관리하는 것이 적용이 휠씬 빠르고 직관적인 것 같습니다.


📄 Key Questions

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

Virtual DOM은 UI의 이상적인 또는 “가상”적인 표현을 메모리에 저장하고 ReactDOM과 같은 라이브러리에 의해 “실제” DOM과 동기화하는 프로그래밍 개념입니다.
DOM의 가벼운 복사본으로, 웹 애플리케이션의 상태 변화를 메모리 내에서 빠르게 처리하고 최소한의 DOM 업데이트를 통해 변화를 반영하는 방식입니다.
실제 DOM은 웹 페이지의 구조와 내용을 브라우저가 이해하고 렌더링하는 데 사용되는 구조화된 트리 모델입니다.
반면, Virtual-DOM은 변화가 있을 때 전체 트리를 다시 그리지 않고 변화가 필요한 부분만 식별하여 DOM에 효율적으로 반영함으로써,
불필요한 DOM 조작을 최소화하고 애플리케이션의 성능을 향상시키는 주요 차이점을 가집니다.
주로 React, Vue 등 라이브러리 및 프레임워크에서 널리 사용되어집니다.

이점

  1. 효율적인 업데이트
    Virtual-DOM은 애플리케이션의 상태가 변경될 때마다 전체 UI를 처음부터 다시 그리는지 않고, 변경된 부분만 실제 DOM에 반영됩니다.
    이는 DOM 조작 비용을 줄여 성능을 향상시킵니다.

  2. 빠른 성능
    Virtual-DOM은 메모리 내에서 작동하기 때문에, 변경사항을 빠르게 계산하고 최소한의 실제 DOM 업데이트로 결과를 반영할 수 있습니다.
    이는 특히 복잡한 인터페이스에서 성능 이점을 제공합니다.

  3. 크로스 플랫폼 호환성
    Virtual-DOM을 사용하면, 웹 브라우저 뿐만 아니라 모바일 애플리케이션(React Native와 같은)에서도 UI를 렌더링할 수 있습니다.
    이는 개발자가 다양한 플랫폼에서 일관된 사용자 경험을 제공할 수 있도록 합니다.
    image

    출처 : https://www.wikitechy.com/interview-questions/reactjs/what-is-react-dom/


2. 미션을 진행하면서 느낀, React를 사용함으로서 얻을수 있는 장점은 무엇이었나요?

  1. 다양한 라이브러리(prettier, eslint, styled-component)를 사용할 수 있어 다양한 기능들을 편리하게 적용할 수 있었습니다.

  2. 전 과제에서 할 일 목록을 구현할 때, DOM 조작을 이용해서 element들을 추가하고, 삭제해서 관리했는데,
    이번 과제에서는 useState를 이용해서 할밀들을 배열로 관리하여, 보다 더 쉬운 아이디어를 활용하여 구현이 가능했습니다.

  3. 이번 과제에선 한가지 기능을 구현해서 컴포넌트를 통해 재사용성 활용을 하지 못했는데, 확실히 컴포넌트를 사용하여 UI를 구축하면,
    코드의 재사용성을 높이고, 대규모 애플리케이션의 개발과 유지보수를 용이할 것을 느꼈습니다.


3. React에서 상태란 무엇이고 어떻게 관리할 수 있을까요?

React에서 상태(state)는 컴포넌트의 상태 정보를 담고 있는 객체로,
컴포넌트의 동작, 콘텐츠, 그리고 렌더링에 영향을 미치는 데이터를 말합니다.
상태는 동적인 데이터를 다룰 때 중요하며, 사용자 상호작용이나 시간의 경과에 따라 변경될 수 있습니다.

image

출처 : https://dev.to/stuxnat/final-react-project-2poi

  1. 컴포넌트 내부 상태(State)
    각 React 컴포넌트는 자신의 state 객체를 가질 수 있으며,
    this.setState()(클래스 컴포넌트) 또는 useState 훅(함수 컴포넌트) 을 사용하여 상태를 업데이트할 수 있습니다.
    상태가 변경될 때마다 React는 컴포넌트를 재렌더링하여 사용자 인터페이스를 최신 상태로 유지합니다.

  2. React Hooks
    useState, useReducer, useContext와 같은 React Hooks는 함수 컴포넌트에서 상태 관리를 보다 선언적으로 할 수 있게 해줍니다.
    useState는 간단한 상태 값 관리에 사용되며, useReducer는 복잡한 상태 로직을 다룰 때 유용합니다.
    useContext는 Context API와 함께 사용되어 컴포넌트 트리를 통한 상태 공유를 간소화합니다.

  3. Redux, Recoil 상태 관리 라이브러리
    Recoil
    애플리케이션 전역에서 상태를 관리할 수 있으며, 컴포넌트 간 상태 공유가 용이해집니다.
    특히, 원자(atom)라는 개념을 사용하여 상태의 단위를 정의하고, 선택자(selector)를 통해 상태를 파생시키는 기능을 제공합니다.

    Redux
    전체 애플리케이션의 상태를 하나의 저장소(store)에서 관리합니다.
    이 저장소는 애플리케이션의 single source of truth으로 작동합니다.
    Redux는 액션(action)과 리듀서(reducer)를 사용하여 상태 변화를 관리합니다.
    액션은 상태 변화를 일으키는 사건을 설명하는 객체이며, 리듀서는 이러한 액션을 받아 이전 상태를 새 상태로 변환하는 순수 함수입니다.


4. Styled-Components 사용 후기 (CSS와 비교)

Styled-Component는 컴포넌트 기반 스타일링으로 똑같은 스타일 속성을 컴포넌트로 재사용하는 것이 편리했습니다.
또 JavaScript 파일 내에 스타일과 컴포넌트 로직이 함께 있기 때문에,
해당 태그 관련 코드를 찾고 관리하기가 더 쉬워 CSS에 비해 스타일 수정이 빠르고 편리했습니다.

하지만 한가지 아쉬운점은 단순히 html 구조를 변경하고 추가할때 스타일속성을 적용하려고 컴포넌트를 생성하고 연결하는 과정이 다소 번거로운 작업이라 생각했습니다.


Copy link

@Programming-Seungwan Programming-Seungwan left a comment

Choose a reason for hiding this comment

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

아예 스타일드 컴포넌트를 파일 하나에서 전체적으로 설정하고, 나중에 필요한 곳에서 import하여 쓰시는 것이 굉장히 인상 깊었습니다.
또한 로컬 스토리지에 저장하는 자료 구조도 잘 설계하시고 깔끔하고 직관적으로 렌더링 하시는 모습에서 많이 배울 수 있었습니다.
좋은 코드 잘 봤습니다 :)

Comment on lines +40 to +48
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"eslint": "^8.0.1",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.34.1",
"prettier": "3.2.5"

Choose a reason for hiding this comment

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

eslint로 문법 정적 검사기를 적용하고, prettier을 통해 코드 포맷팅을 관리해주신 것 좋습니다! 이를 devDependencies에 추가하여 배포 환경에서의 불필요한 설치를 막고 다른 동료 개발자들에게도 동일하게 적용하여 추후의 git 충돌을 막을 수 있을 것 같아요 :)

},
plugins: ["react"],
rules: {
"react/react-in-jsx-scope": "off",

Choose a reason for hiding this comment

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

매번 import React 뭐시기 directive를 써주는 것은 굉장히 귀찮은 일이죠!
실제로 React 버전 17부터 이를 내부적으로 알아서 추가해주기 때문에 개발자가 일일히 불필요한 저 다이렉티브를 추가해줄 필요는 없다고 합니다! 관련 린트 설정 좋습니다!
참고 레퍼런스1
참고 레퍼런스2

@@ -1,7 +1,11 @@
import TodoListPage from "./pages/todoList/todoList";
import { GlobalStyle } from "./styles/GlobalStyles";

Choose a reason for hiding this comment

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

매번 다른 컴포넌트들을 import 해올 때, 상대 경로로 적어주는 것이 약간 가독성을 해친다는 생각이 들었어요(근데 저도 이렇게 과제 했습니다....🤣). 유담님 코드 구경하는데 jsconfig.json 파일에서 절대 경로를 설정해주는 것을 보고 리팩터링 해보시면 좋을 것 같습니다.
유담님 코드 레퍼런스

Comment on lines +7 to +8
<GlobalStyle />
<TodoListPage />

Choose a reason for hiding this comment

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

가장 최외곽 컴포넌트에서 프로젝트의 구조를 알 수 있도록 두 개의 컴포넌트만으로 깔끔하게 구성하신 것이 좋습니다.

Choose a reason for hiding this comment

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

하나의 페이지이므로 TodoListPage로 접근해서 명확하게 엔트리포인트가 보이지만 내부에 구성하는 컴포넌트가 많아서 나중에 유지보수를 위해선 분리하는 것도 좋을 것 같아요

Comment on lines +1 to +265
export const CheckBoxImg = styled.img`
width: 20px;
height: 20px;
margin: 0 15px 0 0px;
fill: #788bff;
`;

export const TodoInput = styled.input`
width: 100%;
height: 50px;
background-color: #252423;
outline: none;
border: none;
color: #e9ecef;
padding: 10px 28px;
font-size: 0.73rem;
::placeholder {
height: 45px;
padding: 8px;
font-size: 0.73rem;
}

@media (max-width: 768px) {
height: 45px;
}
`;

export const SubmitBtn = styled.button`
cursor: pointer;
background-color: #252423;
border: 1px solid #788bff;
width: 40px;
height: 26px;
border-radius: 10px;
font-size: 0.82rem;
color: #788bff;
:hover {
background-color: #3c3a39;
}

@media (max-width: 768px) {
width: 40px;
height: 25px;
font-size: 10px;
}
`;

export const TodoList = styled.div`
width: 100%;
list-style: none;
`;

export const TodoListLi = styled.li`
width: 100%;
height: 52px;
border-radius: 10px;
font-size: 1rem;

display: flex;
justify-content: space-between;

align-items: center;
background-color: #252423;
padding-right: 5px;
margin: 5px 0px;
padding: 0 15px 0 15px;
color: #cdcdcd;

${animationStyles}

@media (max-width: 768px) {
height: 45px;
}
`;
export const TodoListSpan = styled.span`
width: 100%;
padding: 0px 26.1px;
font-size: 0.73rem;
`;

export const TodoListBtn = styled.button`
cursor: pointer;
background-color: #252423;
border: 1px solid #788bff;
width: 40px;
height: 26px;
border-radius: 10px;
font-size: 0.8rem;
color: #788bff;

:hover {
background-color: #3c3a39;
}

@media (max-width: 768px) {
width: 40px;
height: 25px;
font-size: 10px;
}
`;

Choose a reason for hiding this comment

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

아예 스타일 관련 css-in-js 코드를 다른 파일에 분리하여 프로젝트 구성을 한 것도 좋은 것 같습니다! 실제 컴포넌트 UI를 작성하는 파일에서는 이를 import하여 쓰면 되니까요!
다만 개인적으로 styled-components 라이브러리의 큰 매력은 css 코드와 Javascript 코드가 동일한 파일에 위치해서 관련 스타일링을 바꿔줄 때마다 여러 파일을 돌아다니는 것이 아닌, 한 파일에서 적용할 수 있는 점이라고 생각해요. 당연히 그냥 제 생각입니다.
유명한 Javascript 개발자인 kent c dodds 님의 colocation 관련 포스팅 레퍼런스를 첨부합니다 :) 블로그 링크

Copy link
Member Author

Choose a reason for hiding this comment

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

한 파일내에 쓰면 코드가 길어져서 불편할 거라 생각했는데, 한번 직접 시도해보고 경험해봐야겠습니다. 감사합니다!

@@ -0,0 +1,134 @@
import { useEffect, useState } from "react";
import * as T from "./todoList.styles";

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.

저도 놀랐어요! 저는 한 js 파일 내에서 styled-components로 스타일들을 적용하고 관리하는 편인데 이렇게 객체로 받아서 활용하면 중복된 css 작성을 방지할 수 있을 것 같아요.
(제 코드의 버튼 컴포넌트들에 활용해봐야겠어요 감사합니다)
다만 todoList.js 한 파일에서 모든 기능을 구현하셨을 때보다는 컴포넌트로 쪼개서 구현하셨을 때 이 방법이 더 잘 쓰일 것 같아요!!

const indexToDelete = parseInt(event.currentTarget.value, 10);

setDeleteIndexAnimation(indexToDelete); // 삭제 애니메이션 시작
setTimeout(() => {

Choose a reason for hiding this comment

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

삭제 애니메이션 구현을 저도 구현해보고 싶었는데, setTimeout() 함수를 이용해야겠다는 생각은 미처 못했습니다! 좋은 코드에서 많이 배우고 갑니다.

<T.InputCheckImg alt="addTodo Icon" />
<T.TodoInput
type="text"
onChange={onChangeTodo}

Choose a reason for hiding this comment

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

해당 핸들러 함수는 사용자가 글자 하나를 입력할 때마다 트리거 되어서 매번 상태를 업데이트 하는 것으로 보입니다! 이 부분도 개인적인 취향이지만 저 같은 경우는 실제로 사용자가 form을 제출할 때에만 딱 한번 상태를 변경하는 것으로 퍼포먼스 향상을 구현하려고 했습니다.
위 개념은 controlled component vs uncontrolled component 의 개념인데 관련해서 알아보셔두 좋을 것 같아요. 관련 레퍼런스 남깁니다.

Choose a reason for hiding this comment

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

상태가 업데이트됨과 동시에 todoList.js 전체가 렌더링되고있어서 uncontrolled component로 관리하면서 추가로 컴포넌트를 분리해도 좋을 것 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

onChange 함수가 이런 문제가 있군요.. 첨 알아갑니다!. uncontrolled component 좋은 개념 감사합니다.

<T.TodoList>
{todoList?.map((item, index) => (
<T.TodoListLi
key={item.id}

Choose a reason for hiding this comment

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

key 속성을 통해서 렌더링 최적화를 구현해주신 것 좋습니다!

value={index}
className={`${item.id === addedItemId ? "animate-slide-down" : ""} ${deleteIndexAnimation === index ? "animate-fade-out" : ""}`}
>
{item.checked ? (

Choose a reason for hiding this comment

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

관련 체크 속성을 사용하기 이해 로컬 스토리지에 저장할 자료에 checked 속성을 넣어주시고 삼항 연산자를 이용해 조건부 렌더링 해주신 것 좋습니다 :)

Copy link

@Shunamo Shunamo left a comment

Choose a reason for hiding this comment

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

2주차 과제도 1등으로 제출하셨네요 과제하시느라 수고하셨어요!
애니메이션 효과가 인상적이네요 구경하는 동안 재밌었습니다 ㅎㅎ
코드도 전체적으로 깔끔해서 리뷰하면서 편안했어요~
새로운 스타일링 방법 잘 배워갑니다! 새로운 속성도 알게되어서 기뻤어요 🤩

@@ -0,0 +1,134 @@
import { useEffect, useState } from "react";
import * as T from "./todoList.styles";
Copy link

Choose a reason for hiding this comment

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

저도 놀랐어요! 저는 한 js 파일 내에서 styled-components로 스타일들을 적용하고 관리하는 편인데 이렇게 객체로 받아서 활용하면 중복된 css 작성을 방지할 수 있을 것 같아요.
(제 코드의 버튼 컴포넌트들에 활용해봐야겠어요 감사합니다)
다만 todoList.js 한 파일에서 모든 기능을 구현하셨을 때보다는 컴포넌트로 쪼개서 구현하셨을 때 이 방법이 더 잘 쓰일 것 같아요!!

// 로컬스토리지에서 할일 불러오기
const savedTodo = localStorage.getItem("todoItem");
return savedTodo ? JSON.parse(savedTodo) : [];
});
Copy link

Choose a reason for hiding this comment

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

useState의 초기값을 함수형 업데이트로 구현하신 부분 정말 좋은 것 같아요!
저도 이번에 알게 되었는데,
초기값 설정에 함수를 사용하면 해당 로직이 컴포넌트가 랜더링 될 때마다 실행되는 것이 아니라
초기 랜더링 때만 실행되어서 성능 최적화에 좋다고 하네요!!

};

const onClickDelete = (event) => {
const indexToDelete = parseInt(event.currentTarget.value, 10);
Copy link

Choose a reason for hiding this comment

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

할일의 value 값을 얻어서 인덱스에 바로 접근하는 방식이 직관적이라서 좋았어요!
저는각 항목별로 현재 날짜를 사용해서 임의의 ID를 부여하고 이에 접근해서 삭제하는 방법으로 삭제 핸들러를 구현했었는데, 이렇게 인덱스에 직접 접근하는게 더 간결하고 직관적인 방법인 것 같아요

index === currentIndex ? { ...item, checked: !item.checked } : item,
);
setTodoList(updatedTodo);
};
Copy link

Choose a reason for hiding this comment

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

checked 상태 반전 로직이 간단해서 이해하기 편하네요!

Comment on lines +43 to +47
setTimeout(() => {
setTodoList(todoList.filter((_, index) => index !== indexToDelete));
setDeleteIndexAnimation(null); // 애니메이션 후 상태 업데이트
}, 300); // setTimeout의 시간은 애니메이션의 지속 시간과 일치해야 합니다.
};
Copy link

Choose a reason for hiding this comment

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

삭제 애니메이션 멋지네요 ㅎㅎ

다만 setTimeout을 사용할 때는 컴포넌트가 언마운트(삭제)되기 전에 타이머를 명확하게 정리해야 메모리 누수를 방지할 수 있대요!!

그래서 clearTimeout을 호출해야 하는데,
useEffect 내부에서 setTimeout을 호출하고,
return문에 clearTimeout을 호출해서
타이머를 정리해주면
컴포넌트가 사라질 때 메모리 누수를 방지할 수 있다고 합니다!!

Suggested change
setTimeout(() => {
setTodoList(todoList.filter((_, index) => index !== indexToDelete));
setDeleteIndexAnimation(null); // 애니메이션 후 상태 업데이트
}, 300); // setTimeout의 시간은 애니메이션의 지속 시간과 일치해야 합니다.
};
useEffect(() => {
const timerId = setTimeout(() => {
setTodoList(todoList.filter((_, index) => index !== indexToDelete));
setDeleteIndexAnimation(null);
}, 300);
// 컴포넌트 언마운트되기 전에 clearTimeout 호출하기
return () => clearTimeout(timerId);
}, [todoList, indexToDelete]);
// 의존성 배열에 todoList와 indexToDelete추가!!

관련 블로그입니다!!

Copy link
Member Author

Choose a reason for hiding this comment

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

좋은 정보 감사합니다! 👍

onChange={onChangeTodo}
value={todo}
placeholder="할 일을 입력해주세요."
maxLength="45"
Copy link

Choose a reason for hiding this comment

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

글자수 제한을 maxLength로 할 수 있다니!!
새로운 속성 배워갑니다!!!
나중에 잘 활용하겠습니다 감사합니다~~

Comment on lines +83 to +84
<T.TodoInput
type="text"
Copy link

Choose a reason for hiding this comment

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

여기에 autofocus 만 추가하면 인풋칸에 자동으로 포커싱 되어서 편하더라구요. UX 측면에서 좋은 수정이 될 것 같아요~!

Suggested change
<T.TodoInput
type="text"
<T.TodoInput
type="text"
autoFocus

Copy link
Member Author

Choose a reason for hiding this comment

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

오 autoFocus 너무 좋은거같아요.. 좋은 정보 감사합니다

Comment on lines +206 to +210
@media (max-width: 768px) {
width: 40px;
height: 25px;
font-size: 10px;
}
Copy link

Choose a reason for hiding this comment

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

반응형까지 고려하시는 부분 멋져요! 세심하시네요

}
`;

const animationStyles = css`
Copy link

Choose a reason for hiding this comment

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

저도 배워갑니다..!!

}
`;

export const NotCheck = styled(NotCheckImg)`
Copy link

Choose a reason for hiding this comment

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

저는 이미지 스타일링을 할 때 <img>태그에 styled-components 를 적용하는 방식을 사용하는데,
동혁님처럼 직접 이미지를 컴포넌트로 가져와서 직접 스타일링하는 방식이 더 직관적이라 이해도 잘 되고 재사용하기도 편해서 협업할 때 되게 유용할 것 같아요!! 많이 배워갑니다

Copy link

@westofsky westofsky left a comment

Choose a reason for hiding this comment

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

안녕하세요 프론트운영진 배성준입니다~~~~~

애니메이션 디테일이랑 반응형까지 너무 좋았어요!!!!
애니메이션 구현에서 느낄 수 있듯이 코드에도 되게 신경을 많이 쓴 것 같아서 재밌게 봤습니다 ㅎㅎ
Todo는 비교적 작은 기능구현들이라 괜찮을 지 몰라도 프로젝트 규모가 커지면
컴포넌트 분리를 하는게 유지보수 측면에서 좋아서 미리 연습을 해도 좋을 것 같습니다!!
다음 과제도 기대하겠습니다 ㅎㅎㅎ

Comment on lines +7 to +8
<GlobalStyle />
<TodoListPage />

Choose a reason for hiding this comment

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

하나의 페이지이므로 TodoListPage로 접근해서 명확하게 엔트리포인트가 보이지만 내부에 구성하는 컴포넌트가 많아서 나중에 유지보수를 위해선 분리하는 것도 좋을 것 같아요

<T.InputCheckImg alt="addTodo Icon" />
<T.TodoInput
type="text"
onChange={onChangeTodo}

Choose a reason for hiding this comment

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

상태가 업데이트됨과 동시에 todoList.js 전체가 렌더링되고있어서 uncontrolled component로 관리하면서 추가로 컴포넌트를 분리해도 좋을 것 같습니다!

Comment on lines +105 to +109
<T.TodoListSpan
style={{ textDecoration: "line-through", color: "#808080" }}
>
{item.text}
</T.TodoListSpan>

Choose a reason for hiding this comment

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

props를 이용하여 구분해도 좋을 것 같아요! 혹은 간단하게 className을 주고 style에서 class 접근자로 설정해도 좋을 것 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

오 좋은 아이디어 감사합니다~!

Comment on lines +6 to +27
const slideDownFadeIn = keyframes`
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
`;

// 할 일 삭제 시 애니메이션
const fadeOutScaleDown = keyframes`
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.9);
}
`;

Choose a reason for hiding this comment

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

애니메이션 너무 이뻐요!!

Comment on lines +2 to +4
import { ReactComponent as NotCheckImg } from "../../assets/NotCheck.svg";
import { ReactComponent as CheckImg } from "../../assets/checkComplete.svg";
import { ReactComponent as InputCheck } from "../../assets/check.svg";

Choose a reason for hiding this comment

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

svg를 React 컴포넌트로 사용하는 방식도 좋은 것 같아요 ㅎㅎ

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