-
Notifications
You must be signed in to change notification settings - Fork 10
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주차] 김수현 미션 제출합니다. #10
base: master
Are you sure you want to change the base?
Conversation
2. 입력값 존재 여부에 따라 색상 변경 3. 전역 폰트 추가
2. 엔터키 입력 핸들러 구현 3. TodoList 컴포넌트 구현
2. 완료시에도 선택 가능
2. ProgressStatusNumber 컴포넌트 제작 3. 새로운 할 일 추가시 맨 위로 스크롤바 올라가는 기능 구현 4. 각종 애니메이션, 스타일 추가
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.
수현님 코드 리뷰를 하면서 깔끔한 코드, 다양한 애니메이션, input focusing 등 편리하고 디테일한 기능들, 적절한 컴포넌트 분리까지 많은 것을 배워갈 수 있었어요!!
수고하셨습니다~!
border-bottom: 1.5px solid ${props => props.hasContent ? '#4A90E2' : '#ccc'}; //입력된 값 있을 때 파란색으로 변경 | ||
color: ${props => props.hasContent ? '#4A90E2' : '#000'}; |
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.
이런 디테일 너무 좋네요!!
</Header> | ||
<InputContainer> | ||
<TodoInput | ||
autoFocus //input 칸에 자동 포커싱하기!! |
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.
오오 autoFocus
는 몰랐던 속성인데 배워갑니다!! 제 과제에 바로 적용해봐야겠어요 ㅎㅎ
transition: transform 0.1s ease; | ||
&:active { | ||
transform: scale(0.9); | ||
} |
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.
귀엽고 디테일한 애니메이션 너무 좋습니다~!
const handleAddTodo = () => { | ||
if (!inputValue.trim()) return; | ||
const newTodo = { id: Date.now(), text: inputValue, isCompleted: false, isSelected: false }; | ||
setItems(prevItems => [...prevItems, newTodo]); |
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.
오 저는 prevState를 생각하지 못했는데 prevState를 이용하는게 훨씬 가독성이 좋을 것 같아요!
저는 이 글에 있는 첫 번째 방식으로 구현했고 수현님은 두 번째 방식으로 구현하셨는데, 둘의 차이점에 대한 내용이 나와있으니 한번 읽어보시면 도움이 될 것 같아요!
useEffect(() => { | ||
// 새로운 할 일을 추가했을 때 스크롤이 자동으로 이동할 수 있도록 | ||
if (todoList.length > prevTodoListLength && lastTodoRef.current) { | ||
lastTodoRef.current.scrollIntoView({ behavior: 'smooth' }); | ||
} | ||
setPrevTodoListLength(todoList.length); | ||
}, [todoList.length, prevTodoListLength]); |
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.
너무 편리한 UX 디자인이네요! 배워갑니다!!
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.
과제 고생하셨어요.
디자인이랑 애니메이션 구현까지 고민한 흔적이 보이고 과제도 욕심있게 열심히 한 것 같아 저도 좋은 자극 받고 갑니다! 완료된 할 일도 맨밑으로 정렬되는 디테일 좋아요.
그리고 할 일 생성할때 1개가 아닌 2개가 생성되는 버그가 있어서 나중에 디버깅하면 좋을 것 같습니다~!
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.
작은 프로젝트라도 버튼 컴포넌트 만들어서 재사용성 향상 시키는 디테일 너무 좋아요.
import React from "react"; | ||
import styled from "styled-components"; | ||
|
||
const AddButton = ({ onClick }) => { |
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.
저 같은 경우에는 컴포넌트파일에는 컴포넌트에 대한 변수 및 함수를 몰아 넣어서 관리하는 편인데 이런식으로 onClick 함수를 받아서 관리하는 것도 좋은 것 같아요.👍
const StyledButton = styled.button` | ||
background-color: transparent; | ||
border: none; | ||
cursor: pointer; | ||
transition: transform 0.1s ease; | ||
&:active { | ||
transform: scale(0.9); | ||
}padding: 0; | ||
`; |
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.
Add 버튼이랑 스타일이 똑같아서 styles.js 공통 스타일 파일을 만들어서 관리하는 것도 좋은 아이디어 같습니다~!
|
||
|
||
const DateContainer = styled.div` | ||
background-color: transeparent; |
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.
background-color: transparent; 오타 있어요!
const DateBar = () => { | ||
const today = new Date(); | ||
const year = today.getFullYear(); | ||
const month = today.getMonth() + 1; | ||
const date = today.getDate(); | ||
|
||
// 0(일요일)부터 6(토요일)까지 숫자로 반환 | ||
const week = ["일", "월", "화", "수", "목", "금", "토"]; | ||
const dayOfWeek = week[today.getDay()]; // 현재 요일 | ||
|
||
// 한글로 변환!! | ||
const formattedDate = `${year}년 ${month}월 ${date}일 ${dayOfWeek}요일`; | ||
|
||
return <DateContainer>{formattedDate}</DateContainer>; | ||
}; |
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.
이건 제가 사용했던 방법인데 ES6의 Intl.DateTimeFormat을 사용해 날짜를 포매팅하면 코드의 가독성을 높이고, 다국어 처리에도 용이합니다 :)
const DateBar = () => { | |
const today = new Date(); | |
const year = today.getFullYear(); | |
const month = today.getMonth() + 1; | |
const date = today.getDate(); | |
// 0(일요일)부터 6(토요일)까지 숫자로 반환 | |
const week = ["일", "월", "화", "수", "목", "금", "토"]; | |
const dayOfWeek = week[today.getDay()]; // 현재 요일 | |
// 한글로 변환!! | |
const formattedDate = `${year}년 ${month}월 ${date}일 ${dayOfWeek}요일`; | |
return <DateContainer>{formattedDate}</DateContainer>; | |
}; | |
const DateBar = () => { | |
const today = new Date(); | |
const formatter = new Intl.DateTimeFormat('ko-KR', { | |
year: 'numeric', | |
month: 'long', | |
day: 'numeric', | |
weekday: 'long', | |
}); | |
const formattedDate = formatter.format(today); | |
return <DateContainer>{formattedDate}</DateContainer>; | |
}; |
flex: 1; | ||
border: none; | ||
border-bottom: 1.5px solid ${props => props.hasContent ? '#4A90E2' : '#ccc'}; //입력된 값 있을 때 파란색으로 변경 | ||
color: ${props => props.hasContent ? '#4A90E2' : '#000'}; |
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: ${props => props.hasContent ? '#4A90E2' : '#000'}; | |
color: ${props => props.value.length > 0 ? '#4A90E2' : '#000'}; |
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.
저번 과제에서도 구현했지만 진행률 표시하는 추가기능 아이디어 너무 좋은 것 같아요 :)
${props => props.filled && css` | ||
animation: ${fillAnimation} 1s ease-out forwards; //부드럽게 박스 색깔 채우기 | ||
background-color: #D0CFFF; | ||
`} | ||
${props => props.allCompleted && css` | ||
animation: ${completeAnimation} 2s ease-out forwards; // 모든 항목이 완료되었을 때 색 변하기 | ||
`} |
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.
애니메이션이 중복으로 처리되고 있는 것 같아요. allCompleted 조건이 참일 경우에만 completeAnimation을 적용하고, 그렇지 않고 filled 조건이 참일 때는 fillAnimation을 적용하면 좋을 것 같아요.
이런 느낌으로..?
${props => props.filled && css` | |
animation: ${fillAnimation} 1s ease-out forwards; //부드럽게 박스 색깔 채우기 | |
background-color: #D0CFFF; | |
`} | |
${props => props.allCompleted && css` | |
animation: ${completeAnimation} 2s ease-out forwards; // 모든 항목이 완료되었을 때 색 변하기 | |
`} | |
${props => props.allCompleted ? css` | |
animation: ${completeAnimation} 2s ease-out forwards; | |
` : props.filled ? css` | |
animation: ${fillAnimation} 1s ease-out forwards; | |
background-color: #D0CFFF; | |
` : ''} |
font-weight: bold; | ||
font-size: 16px; | ||
font-weight: bold; |
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.
중복!
const floatAndGrowAnimation = keyframes` | ||
0%, 100% { | ||
transform: translateY(0); | ||
font-size: 14px; | ||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1); | ||
} | ||
50% { | ||
transform: translateY(-5px); | ||
font-size: 16px; | ||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); | ||
} | ||
`; |
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.
애니메이션 적용할때는 font-size 대신에 scale을 사용해요. 애니메이션에 의한 레이아웃 변화는 사용자 경험에 부정적인 영향을 줄 수 있기 때문에 그렇다고 해요.
scale은 이런식으로 작성하면 됩니다 :)
const floatAndGrowAnimation = keyframes` | |
0%, 100% { | |
transform: translateY(0); | |
font-size: 14px; | |
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1); | |
} | |
50% { | |
transform: translateY(-5px); | |
font-size: 16px; | |
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); | |
} | |
`; | |
const floatAndGrowAnimation = keyframes` | |
0%, 100% { | |
transform: translateY(0) scale(1); | |
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1); | |
} | |
50% { | |
transform: translateY(-5px) scale(1.1); | |
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); | |
} | |
`; |
2주차 미션: React-Todo
느낀점
저번 주차에 만들었던 바닐라 todo를 그대로 리액트로 구현하려고 하니 생각보다 어려웠습니다. ㅠㅠ
처음에는 각각의 요소들을 컴포넌트로 쪼개고 구상하는 일들이 귀찮았지만,
여러개의 컴포넌트로 나눠서 작업을 하니까 가독성이 좋아 수정할 때도 편했던 것 같습니다.
그리고 style-component로 스타일을 적용하니까 바닐라js보다 시간도 적게 걸리고 편했습니다.
제가 생각하는 리액트의 장점은 한페이지에서 여러 변화?를 주고 관리하는게 쉽다는 것이었는데,
이를 잘 살리지 못한 것 같아 아쉬움이 남습니다.
작업을 계획하면서 최대한 이전의 코드리뷰들을 반영해보려고 노력하였으나
100% 잘 이루어진 것 같지는 않습니다. ㅜㅜ
그리고 일주일 규모로 투두리스트를 만들어보려고 기획했으나 흐지부지 돼버린게 아쉽습니다.ㅠㅠ
다음에는 더 열심히 하도록 하겠습니다~!!
배포링크
배포링크
Key Questions
DOM이란?
→ HTML과 JavaScript를 이어주는 역할!!
Virtual DOM이란?
→ 실제 DOM에 접근하여 조작하지 않고, 이를 추상화한 자바스크립트 객체를 구성하여 사용하는 방식
→ DOM의 상태를 메모리 위에 계속 올려두고, DOM에 변경이 있을 경우 해당 변경을 반영함
리액트는 Virtual DOM에 있던 이전의 내용과, Virtual DOM에 있는 현재의 내용을 비교해서
바뀐 부분만 실제 DOM에 적용하여 DOM을 업데이트해 성능을 향상시킨다!!
우선 저에게 표면적으로 다가왔던 장점은 개발 속도 증가입니다.
리액트를 사용하니까 변경 사항이 새로고침이나 디버깅을 할 필요 없이 즉각적으로 화면에 적용되어 낭비되는 시간을 줄일 수 있었습니다.
다음으로는 컴포넌트화의 편리함입니다.
각 기능과 스타일을 작은 단위로 쪼개서 재사용할 수 있게 되니까, 코드가 훨씬 깔끔해지고 관리하기도 쉬워져습니다.
마지막으로는 간편한 상태관리법입니다.
이번 미션을 진행하면서 저는 여러가지 훅 중에서 useState, useRef, useEffect만을 사용했는데,
함수형 컴포넌트 안에서 상태관리가 완전 쉬워져서 바닐라js로 작업할 때보다 훨씬 수월했어요!
React에서의 상태란?
→ 컴포넌트의 렌더링을 결정짓는 데이터의 집합
→ 상태가 변경될 때마다 React는 컴포넌트를 다시 렌더링하여 사용자 인터페이스를 최신 상태로 유지함!!
React에서 상태를 관리하는 방법
→ 각각의 컴포넌트마다 state가 있을 수 있음
→ useState 같은 hook으로 관리함
부모→ 자식의 흐름으로 데이터를 전달할 수 있음
→ 자식 컴포넌트에게 props을 전달해서 state를 변경할 수 있음!!
[Redux(리덕스)란? (상태 관리 라이브러리) - 하나몬 (hanamon.kr)](https://hanamon.kr/redux%EB%9E%80-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/)
애플리케이션의 전역 상태를 관리하는 라이브러리로, 애플리케이션의 상태를 하나의 store에서 관리함.
action을 dispatch해서 reducer 함수를 통해 상태를 업데이트함.
주로 큰 규모의 애플리케이션에서 상태를 일관되고 예측 가능하게 관리할 수 있음.
작은 규모의 프로젝트에서는 과도한 구성이 될 수 있음
*Hooks: 함수형 컴포넌트에 사용되는 몇 가지 기술
종류
기본 Hooks
추가 Hooks
이중에 useState, useEffect, useContext, useRef만 사용해봄*Recoil: 상태를 "atoms"과 "selectors"로 관리
Atoms: 상태의 일부, 여러 컴포넌트에서 공유될 수 있음
Selectors: 다른 상태에 의존하는 상태를 계산하는데 사용댐
Hooks와 잘 통합되어, Hooks를 사용하는 것과 유사한 패턴으로 상태를 관리할 수 있음.
다음에 Recoil을 써봐야겠음!!
일단 제일 편했던 건 캡슐화 덕분에 다른 컴포넌트랑 충돌도 안나고 컴포넌트명이 한눈에 보여서 구조 파악이 편했습니다.
그리고 컴포넌트 스타일을 직접 관리하니까 컴포넌트와 관련된 모든걸 한 jsx 파일에서 관리 할 수 있어서 파일 구조도 간단했고 직관적이었습니다.
그리고 props으로 조건부 스타일링을 할 수 있어서 자꾸만 동적으로 스타일링을 하고싶어지고.. 신기한 도전을 하게 되는 것 같습니다
필수 요건
- 1주차 미션의 결과물을 그대로 React로 구현합니다. (‼️ todo / done 개수 잊지 마세요 ‼️ )- Functional Components를 사용합니다.- React Hooks만을 사용해 상태를 관리합니다.- (이번주는 Redux, MobX, Recoil, SWR등의 외부 상태관리 라이브러리를 사용하지 않아도 미션 수행에 지장이 없습니다.)