-
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주차] 안혜연 미션 제출합니다. #3
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.
혜연님 고생 많으셨습니다! 제 나름대로 도움이 될만한 코드리뷰를 남겼는데, 혜연님이 의도하신 바가 따로 있는데 제가 잘못 생각한 부분이 있다면 말씀해주세요 ㅎㅎ 혜연님 코드를 보면서 css와 언제 react.memo를 사용해야하는지에 대해 더 공부해야겠다는 생각이 들었어요 ㅠ ㅠ
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.
중간 중간에 let 키워드로 변수를 선언해주셨는데, 이유가 있을까요? 모던 자바스크립트 딥다이브에서 봤었는데, 기본적으로 const를 사용하고, let은 재할당이 필요한 경우에만 한정지어 사용하는 게 좋다고 하더라구요. 의도치 않은 재할당을 방지하기 위해서요!
`; | ||
|
||
export default function ToDoList() { | ||
const savedToDos = JSON.parse(localStorage.getItem('toDoData') || '[]'); // 로컬 스토리지에서 불러오기 |
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.
로컬 스토리지에 저장된 배열이 없을 경우를 대비해서 초기값을 설정해주셨는데 "[]"이 아니라 []이 맞는 표현 같습니다..! 아니면 혹시 의도하신 걸까요?
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.
JSON.parse는 문자열을 인자로 받기 때문에, null이나 배열 리터럴 자체를 처리할 수 없어서 '[]'를 사용했습니다!
src/components/TodayDate.js
Outdated
@@ -0,0 +1,24 @@ | |||
import React from 'react'; |
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.
리액트 17버전 이후부터는 이 import 문을 쓰지 않아도 됩니다!
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.
헉 제가 함수형 컴포넌트 단축키 rfc로 사용했더니 이런 점을 놓쳤네요..!
src/components/InputForm.js
Outdated
line-height: 20px; | ||
cursor: text; | ||
|
||
background-image: url('${plusImg}'); |
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.
svg를 background image로 넣어주셨는데, 이는 SEO 측면에서 안티패턴이라고합니다..! 모던 리액트 딥다이브 책에서도 봤었는데 background-image는 리소스 요청에서 우선순위가 낮아서 보여지지 않다가 갑자기 노출되게 되어 LCP 지표에 악영향을 미친다고 해요. 그 외에도 많은 안 좋은 점들이 있어서 아래 글 참고해보시면 좋을 거 같습니다! 저는 주로 그냥 img 태그로 가져와서 absolute 속성을 주는 편이에요 :)
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.
헉 그렇군요.. 덕분에 알게 되었어요!!
src/pages/ToDoList.js
Outdated
export default function ToDoList() { | ||
const savedToDos = JSON.parse(localStorage.getItem('toDoData') || '[]'); // 로컬 스토리지에서 불러오기 | ||
const [toDoData, setToDoData] = useState(savedToDos); | ||
const [value, setValue] = useState(''); |
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과 연결되는 이 value라는 state는 InputForm 컴포넌트 안에서 선언하는 게 좋을 거 같습니다! 다른 컴포넌트에서는 사용하지 않으니까요:)
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.
제가 컴포넌트 분리하는 과정에 놓쳤네요.. 섬세한 리뷰 감사합니다!!
src/components/List.js
Outdated
// 할 일 목록의 완료 상태 변경하는 함수 | ||
const handleComplete = (id) => { | ||
let newToDoData = toDoData.map((item) => { | ||
if (item.id === id) { | ||
return { ...item, completed: !item.completed }; | ||
} | ||
return item; | ||
}); | ||
setToDoData(newToDoData); | ||
}; |
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.
NIT
항상 변수를 선언을 해주신 다음, setState의 인자로 해당 변수를 넣어주는 패턴으로 코드를 짜시는데 저는 이런 식으로 작성합니다! 참고해주세요 ㅎㅎ
// 할 일 목록의 완료 상태 변경하는 함수 | |
const handleComplete = (id) => { | |
let newToDoData = toDoData.map((item) => { | |
if (item.id === id) { | |
return { ...item, completed: !item.completed }; | |
} | |
return item; | |
}); | |
setToDoData(newToDoData); | |
}; | |
// 할 일 목록의 완료 상태 변경하는 함수 | |
const handleComplete = (id) => { | |
setToDoData((prev) => | |
prev.map((item) => | |
item.id === id ? { ...item, completed: !item.completed } : item | |
) | |
); | |
}; |
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.
헉 삼항 연산자 쓰니까 코드가 훨씬 간결해지네요..! 감사합니다 👍
src/components/List.js
Outdated
&::after { | ||
content: ''; /* 가상 요소에 내용이 없음을 명시 */ | ||
position: absolute; | ||
bottom: 0; | ||
left: 0; | ||
width: calc(100% - 30px); /* 전체 너비에서 30px만큼 줄임 */ | ||
margin-left: 30px; | ||
border-bottom: 1px solid #ccc; | ||
} | ||
|
||
css @media (max-width: 768px) { | ||
padding: 5px; 5px; 5px; 15px; | ||
&::after { | ||
width: calc(100% - 20px); | ||
margin-left: 20px; | ||
} | ||
} | ||
`; |
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 알못이라 이 가상선택자를 사용하신 이유가 뭔지가 궁금하네요 ㅎㅎ 이따 개별 토론 시간에 이야기 나눠봐요! 그리고 아래 미디어 쿼리 부분에 css라고 선언해주신 이유가 있나요?
그리고 스타일드 컴포넌트에서 미디어 쿼리를 사용하실 때 globalStyle에서
export const device = {
tablet: `(min-width: 768px) and (max-width: 1199px)`,
mobile: `(max-width: 767px)`,
};
이렇게 적어두시면 변수처럼 사용할 수 있어요 ~
@media device.tablet{
}
이런 식으로요 ㅎㅎ
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는 오타가 났네요... 미디어쿼리 사용할 때 변수처럼 사용하면 더 간단한 것 같아요!
TextContainer 시작부분부터 ItemContainer의 width 끝까지 밑줄을 추가하고 싶었는데요!
왼쪽 여백을 주고 경계선의 너비를 요소의 전체 너비와 다르게 설정하고 싶어 가상 요소를 추가해주었습니다!
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.
아 그리고 저는 주로 rem 단위를 사용하는데요!
html {
font-size : 62.5%
}
를 global style로 설정해주면 10px = 1rem으로 계산이 되어서 단위 계산을 훨씬 덜 하고 css 코드를 작성할 수 있어요!
rem을 사용하면 좋은 이유에 대한 아티클 남기고 갑니다 !
px 대신 rem을 사용해야하는 이유
그리고 이 아티클에서는 피그마가 rem을 지원하지 않는다고 하지만, 최근에 피그마를 사용해봤을 때 단위를 바꿀 수 있는 기능이 존재했었어요 ㅎㅎ
엠티 이슈 + 오늘 보는 졸업 시험 때문에 코드리뷰가 늦어져서 죄송해요 ㅠㅠ 이따 스터디 시간에 봬요!!
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 reset from 'styled-reset'; | ||
|
||
const GlobalStyles = createGlobalStyle` | ||
${reset} |
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 SlideIn = keyframes` | ||
from { | ||
transform: translateX(100%); | ||
} | ||
|
||
to { | ||
transform: translateX(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.
처음 딱 보고 신기하다고 생각했는데 이렇게 하신거구나..😃 혜연이 진짜 애니메이션 달인이네용...❤️
src/components/InputForm.js
Outdated
background-size: 20px 20px; | ||
`; | ||
|
||
export default function InputForm({ value, setValue, onAddToDo }) { |
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로 넘겨받을때 구조분해할당하신거 너무 좋아요! 저의 경우에는 2개 이상의 props인 경우 가독성을 위해 아래와 같이 쓰는데요, 기능은 같으니까 참고만하시면 될 것 같아요 ㅎㅎ
export default function InputForm({ value, setValue, onAddToDo }) { | |
export default function InputForm(props) { | |
const { value, setValue, onAddToDo } = props; |
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.
여러 개 넘겨 받을 때 민영님 코드처럼 작성하면 가독성이 더 좋을 것 같아요! 감사합니다 👍
src/components/List.js
Outdated
<TextContainer | ||
completed={item.completed} |
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에 props 전달까지 최곤데요 ? ㅎㅎ
그런데 한가지 주의해야할 점이 있는데요 바로 표준 속성 워닝입니당 ㅎㅎ
표준 속성 워닝이란?
React와 styled-components에서는 표준 HTML 속성이 아닌 사용자 정의 속성이 DOM 엘리먼트에 전달되는 것을 기본적으로 허용하지 않아서 발생하는 에러
따라서 styled component 5.1버전 이상부터는 $를 prefix로 써서 warning을 없애고 DOM에 불필요한 속성이 전달되는 것을 막아주었어요 !!
혹시나 구체적인 내용 더 확실히 알고 싶을 수 있으니 관련 아티클 첨부할게요 > <
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.
이 부분은 아래처럼 바꿔주면 되겠죠 ? 😆
<TextContainer | |
completed={item.completed} | |
<TextContainer | |
$completed={item.completed} |
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.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ @Rose-my 저 민영님한테 코드리뷰 받고싶어요.... 넘 정성스러움 민영님이 알려주신 부분 아마 이미 브라우저 콘솔창에서 warning으로 뜨고 있을 거예요! 개발하실 때 콘솔창 확인 자주 해주시면 많은 걸 놓치지 않을 수 있답니다 :)
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.
헉 덕분에 남겨주신 블로그 잘 읽어봤어요!! 또 하나 배워갑니다.!!
src/components/List.js
Outdated
<CheckButtonImg | ||
src={item.completed ? greenCheckBtn : grayCheckBtn} | ||
alt="회색 체크 버튼" | ||
onClick={() => handleComplete(item.id)} |
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.
react로 넘어오면서 시맨틱 요소 까먹기 쉬운데 img 태그에 alt 챙겨준거 짱짱 ㅎㅎ
그런데 button 태그를 사용할 때도 잊지말고 type="button"을 명시하면 좋아요! 😁
button의 기본 타입은 "button"이 아닌 "submit"이기 때문인데요! submit의 경우 폼을 제출하는 이벤트를 발생시켜서 따로 설정을 하지 않는 이상 새로고침에 따라 사용자가 입력한 값을 저장하지 않고 날려버린다고 하네요..🥹
그래서 type="button"을 명시해주어 이 버튼은 그자체로 아무런 이벤트가 없음을 알리고 자바스크립트 click이벤트 등과 연결을 하면 돼요! > <
const TextContainer = styled.div` | ||
width: 100%; | ||
font-size: 1em; | ||
text-decoration: ${(props) => (props.completed ? 'line-through' : '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.
진짜 최고에요... 👍 line-through 속성까지...!
public/index.html
Outdated
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.
lang 속성은 웹 페이지의 언어를 선언하는데요,
lang 속성이란?
현재 페이지의 텍스트가 어떠한 언어로 작성되어 있는지 표기하여 시각적으로 불편하신 사용자 분들께서
스크린 리더와 같은 보조 수단을 통해 웹을 이용하실 때 lang 속성으로 표기한 언어에 알맞도록 발음이 적용되어
웹을 조금 더 편하게 이용하실 수 있도록 도움을 드릴 수 있는 웹 접근성 관련 속성이라고 하네요 😆
아무래도 <html lang="en">
에서 "ko"
로 바꾸는게 낫겠죠 ? > <
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.
그리고 이렇게 불필요한 파일들과 태그는 처음 React 프로젝트를 생성 또는 클론하고, 구현 시작 전 초기세팅 시 싹 지워주고 시작하면 좋아요!! > <
나중에 왜 이 파일 있는데 안썼냐! 하는 경고나 에러가 뜰 수도 있고, 파일명이나 모듈명이 겹치면 골치아파질 수 있기 때문이랍니당 😆
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.
안녕하세요~ 19기 프론트 운영진 변지혜입니다!!
배포화면이 정말 깔끔하고 애니메이션도 잘 들어가 있어서 재밌게 봤습니다ㅎㅎ
그럼 스터디 시간에 뵐게요~!!
src/components/InputForm.js
Outdated
type="text" | ||
placeholder="할 일을 입력하세요." | ||
value={value} | ||
onChange={handleInput} |
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.
handleInput 함수가 하는 역할이 Value를 바꿔주는 것만 있다면
onChange={(e) => setValue(e.target.value)}
로 줄일 수 있을 것 같아요~!
height: 50vh; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: flex-start; | ||
overflow-y: auto; | ||
overflow-x: hidden; |
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.
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.
ToDoBlock에 지정해준 overflow 속성은 전체 투두리스트의 스크롤바를 생성해주어서
다시 보니까 이것과 별개로 ItemContainer
에는 overflow-y: auto;
로 지정을 안해줘서 생긴 문제네요.. ㅜㅜ
각각의 투두 내용이 길어질 경우를 생각 못했네요... 지혜님 꼼꼼한 리뷰 감사합니다 👍
src/components/List.js
Outdated
&::after { | ||
content: ''; /* 가상 요소에 내용이 없음을 명시 */ | ||
position: absolute; | ||
bottom: 0; | ||
left: 0; | ||
width: calc(100% - 30px); /* 전체 너비에서 30px만큼 줄임 */ | ||
margin-left: 30px; | ||
border-bottom: 1px solid #ccc; | ||
} |
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.
따로 border를 주시지 않고 이렇게 가상 요소로 선언하신 이유가 따로 있을까요? 저는 보통 margin과 padding을 활용해서 border-bottom으로만 주는 편이었어서 따로 이유가 있으셨는지 궁금합니다ㅎㅎ
|
||
const ButtonsContainer = styled.div` | ||
display: flex; | ||
animation: ${SlideIn} 0.5s forwards; // 0.5초 동안 애니메이션 실행 |
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.
애니메이션 부드럽게 잘 들어간 거 너무 예쁘더라구요 !! 디테일 짱👍👍입니다!!
`; | ||
|
||
// React.memo를 사용하여 컴포넌트의 불필요한 렌더링을 방지 | ||
export default React.memo(function List({ toDoData, setToDoData }) { |
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.
memo까지 적극적으로 활용해주시는 점 배워갑니다
2주차 미션: React-Todo
배포 링크
기능 구현
기존 기능
추가된 기능
느낀 점
안녕하세요, 19기 프론트 안혜연입니다!
1주차 과제에서 추가로 몇몇 기능을 넣으려고 했으나,, 일단 필수 기능 위주로 구현했습니다.
추가로 스타일을 반응형으로 지정해주려고 했습니다. 평소 자주 쓰는 px 단위가 익숙해서 반응형 구현에 있어 어렵게 느껴졌습니다..
다른 분들은 어떤 단위 위주로 사용하는지,, 피그마로 디자인을 볼 때 px 단위로 나타나는데 직접 다른 단위로 계산해서 사용하는지,,
반응형 구현은 미디어 쿼리로 지정해주시는지 궁금합니다.!!
그리고 Tailwind CSS를 사용하면 반응형 디자인 구현이 훨씬 편리하다는 것 같아 Tailwind CSS도 공부해서 사용해보고 싶습니다.
할 일을 입력할 때마다 할 일 목록들이 불필요하게 렌더링되어 React.memo를 사용해 이를 방지하였습니다.
또 할 일 텍스트를 선택하면 버튼 컨테이너가 나오게끔 슬라이드 효과를 주고 싶어 애니메이션 효과를 지정해주었습니다.
미션 목표
Key Questions
Virtual-DOM은 무엇이고, 이를 사용함으로서 얻는 이점은 무엇인가요?
웹 페이지 빌드 과정(Critical Rendering Path CRP)
→ 돔에 변화가 발생할 때마다 렌더 트리가 재생성해서 성능상 문제가 있다.
Virtual DOM
실제 DOM(Document Object Model)의 가벼운 사본
애플리케이션의 상태가 변경될 때 이전 Virtual DOM에서 변경된 부분만 업데이트하여 실제 DOM 업데이트가 최소화되어 애플리케이션의 성능이 향상됩니다.
미션을 진행하면서 느낀, React를 사용함으로서 얻을 수 있는 장점은 무엇이었나요?
UI를 독립적인 컴포넌트로 나누어 개발할 수 있다는 것이 장점으로 느껴졌습니다. 컴포넌트들은 재사용이 가능하고, 컴포넌트에서 자신이 개별적으로 상태 관리를 할 수 있어 복잡한 UI도 쉽게 관리하고 유지할 수 있습니다.
React에서 상태란 무엇이고 어떻게 관리할 수 있을까요?
상태란 컴포넌트의 상태를 저장하고 관리하는 데이터로 컴포넌트가 동적으로 데이터를 처리하고 UI를 적절히 업데이트할 수 있게 해줍니다.
클래스 컴포넌트 내에서는 this.state를 사용하여 상태를 초기화하고, this.setState 메소드를 사용해 상태를 업데이트합니다. React 16.8부터 도입된 Hooks는 class없이 state를 사용할 수 있게 하여 함수 컴포넌트에서도 상태 관리를 가능하게 합니다.
컴포넌트 트리 안에서 전역 상태를 공유할 수 있도록 만들어진 방법으로 작거나 중간 규모의 애플리케이션에서 유용합니다.
Styled-Components 사용 후기 (CSS와 비교)
css 파일로 스타일을 지정하는 것보다 Styled-Components가 더 편리하게 느껴졌습니다. 별도의 css 파일 없이 하나의 js 파일 안에서 컴포넌트 단위별로 스타일을 지정해줄 수 있다는 점에서 스타일을 관리하기 더 쉬웠습니다. 또한 props나 상태에 따라 해당 스타일을 쉽게 처리할 수 있어 편리했습니다.
링크 및 참고자료