-
Notifications
You must be signed in to change notification settings - Fork 10
[2주차] 이채연 과제 제출합니다. #1
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
과제 수고 많으셨습니다..!
도움이 되었으면 좋겠습니다 ㅎㅎ
특별히 언급하지 않은 부분은 잘 되어있는 거 같아요..!
다만 현재 배포 링크가 공개가 안 되어있는 것 같아서 설정 바꿔주셔야 할 것 같아요!
|
||
.hidden { | ||
display: none; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
먼저, 이번 과제에서는 Styled Component를 사용하면 좋았을 거 같습니다! 특정 스타일, 기능을 가진 컴포넌트를 만들 수 있습니당
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그래도 현재 css에서 보기 편한 구조와 명확한 네이밍이 좋은 것 같습니다!
const prefix = dateStr === todayStr ? '오늘' : dateStr; | ||
const progressText = `${prefix} 할일 ${totalCount}개 중 ${completedCount}개 완료`; | ||
|
||
// ==== UI ==== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
모든 코드를 App.jsx에 박기보다는 컴포넌트 단위로 분리하여서 파일을 나누면 가독성, 재사용성이 더 좋을 것 같습니다..!
Header, Input, Progress, List 등 화면 구성 별로 나누어 두면 좋을 거 같아요..!
}`; | ||
|
||
export default function App() { | ||
// ==== state ==== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상태관리 훅이나 로직 등이 모두 한 파일에 있어서 커스텀 훅을 사용해봐도 좋을 것 같아요..!
<button | ||
className="dateNavBtn" | ||
id="nextDay" | ||
onClick={() => moveToDate(1)} | ||
> | ||
▶ | ||
</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
날짜 변경 버튼을 앞뒤를 같은 class 를 활용한 것 좋은 것 같습니다!
const dateStr = useMemo(() => dateToStr(currentDate), [currentDate]); | ||
const todos = useMemo( | ||
() => todosByDate[dateStr] || [], | ||
[todosByDate, dateStr] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useMemo를 사용한 것 좋은 것 같습니다!
다만 컴포넌트가 분리되어 있다면 useMemo를 사용하는 의미가 훨씬 클 것 같습니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨습니다! 컴포넌트화와 styled-component에 대해서 익혀보시고, 리팩토링해보셨으면 좋겠습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컴포넌트화가 되어있지않고, vanilla.js처럼 모든 로직이 한 파일에 들어있어서 재사용성 면이나, 가독성면에서 떨어지는 것같은 특징이 존재합니다. 첨부링크는 토스에서 컴포넌트화하면 좋은 이유에 대해서 만든 강연이니 참고해서 봐보시면 좋을 듯 합니다
const [nextId, setNextId] = useState(() => { | ||
const savedId = localStorage.getItem('nextId'); | ||
const n = parseInt(savedId || '1', 10); | ||
return Number.isNaN(n) ? 1 : n; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nextId초기값을 1로 설정하면서, 나중 addTodo함수에서 setNextId((n) => n + 1);이렇게 계속 증가만 시키는데 이렇게 관리하게 되면 id키값이 불필요하게 커지게 되는 이슈가 존재합니다.
https://yozm.wishket.com/magazine/detail/2634/
주완님 PR에 있는 내용인데, 이렇게 key를 index로 관리할 때의 안되는 이유에 대해서 잘 설명이 되어있으니까 한 번 참고해보세요!
const totalCount = todos.length; | ||
const completedCount = todos.filter((t) => t.completed).length; | ||
const todayStr = dateToStr(new Date()); | ||
const prefix = dateStr === todayStr ? '오늘' : dateStr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefix라는 변수명보다는 날짜를 담는다는 의미의 변수명이 좋을 듯합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
color 속성 지정의 종류에는 색상명그대로 사용하거나, 16진수, RGB등이 있는데 이 방식을 둘 중에 하나로 통일해줘도 코드의 가독성 면에서 좋은 코드가 될 수 있어요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
styled-component를 사용하지 않은점에서 굉장히 아쉬웠지만, 커스텀태그와 함께 스타일링을 하다보면 구조화가 잘된다는 장점이 존재하는 것 같습니다. 코드리뷰 리팩토링과 함께 사용해보시면 좋을 듯 합니다.
https://opencollective.com/styled-components/updates/thank-you
https://theinnovators.zone/archives/4218
추가적으로 styled-component의 경우 이제는 유지 관리 모드로의 전환이 된다고합니다. tailwind.css도 같이 익혀보는 걸 추천드립니다! (+개인적으로 코드 스타일 작성하는 속도가 비약적으로 빨라서 저는 선호하는 편)
</header> | ||
|
||
<section className="todoInputSection"> | ||
<form className="todoForm" id="todoForm" onSubmit={addTodo}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 form 태그를 통해 데이터를 전송하는 방식으로 택하고 있는데, 이것은 버튼 클릭시 브라우저가 새로고침되는데, SPA방식에서는 불필요한 동작이라 form태그 사용안하는 것을 추천드립니다.
추가적으로 input만 사용하게 된다면 엔터키를 통한 데이터 전송이 어려워서 addEventListener
keydown
을 통해서 등록되도록 처리도 해야합니다.
- 한글은 조합문자라서 enter키를 통해 이벤트 발생 시 이벤트가 두 번 발생되니, isComposing으로 해결하면 좋습니다!
배포 링크
https://react-todo-22nd-git-codus02-chaeyeons-projects-9268a0f8.vercel.app
후기: 리액트를 실제 사용해보는것은 처음이라 리액트 설치하는 방법부터 공부하느라 약간 시간이 빠듯했다. 저번주에 피드백받은 부분들을 수정해서 구현 결과는 같지만 코드를 발전시키고 싶었지만 그러지 못한것이 아쉽다. 확실히 html 파일이 간결해진게 보기는 좋지만 리액트를 왜 쓰는건지는 아직 명확히 이해는 덜됐다. 그리고 리액트를 사용했지만 .jsx 파일을 하나밖에 생성 사용하지 않아 제대로 그 기능을 완전히 아직 사용하지 못한것같다. 얼른 열심히 공부해야할것같다...
그리고 주완님 배포하는것도 도와주셔서 너무 감사하다.. 다음주에도 도와주시겠지
리액트에서는 가상돔 (Virtual Dom)을 사용하는데, 이는 실제 DOM을 모방해 만들어낸것이다. 가상돔은 메모리에 저장된 자바스크립트 객체 형태로 존재한다. DOM을 변경하는 것은 무겁기 때문에 빠른 화면전환을 위해 가상돔을 사용한다. 가상돔은 렌더링 전의 화면과 렌더링 후의 화면 두개의 가상 돔 객체를 유지하며, 이 둘을 비교하며 변경된 부분만 실제 DOM에 반영한다. 이 방법을 통해 변경사항만을 빠르게 파악하고 리렌더링이 가능해졌다.
React.memo()는 props가 변경되지 않으면 이전 렌더링 결과를 재사용해 불필요한 렌더링을 막는다. state, context 가 변경되면 리렌더링이 된다.
useMemo()는 복잡한 계산 결과를 메모이제이션해 의존성 배열 값이 변경될때만 다시 계산한다. 불필요한 계산을 줄인다.
useCallback()는 함수를 메모이제이션해 불필요하게 새로 정의되는 것을 방지한다. 하위 컴포넌트에 함수 props를 전달할때 불필요한 리렌더링을 막는다.
생명주기는 컴포넌트가 생성되고 없어질때까지를 말한다. 생성 (mounting)- 업데이트(updating)- 제거(unmounting) 단계로 이루어져있으며, 각 단계마다 특정한 이벤트가 발생한다. 이러한 생명주기는 클래스형 컴포넌트에서만 사용할 수 있고 함수형 컴포넌트에서는 사용하지 못했으나 Hooks를 이용해 사용이 가능해졌다.
mount는 돔이 웹 브라우저상에 나타나는 단계로 한번만 실행된다. updating은 속성이나 상태가 변경되어 엘리먼트를 업데이트할때 발생하며 여러번 발생한다. unmounting은 엘리먼트를 DOM에서 제거할때 발생하며 한번만 실행된다.