Conversation
corinthionia
left a comment
There was a problem hiding this comment.
안녕하세요 윤정 님~!
리뷰하다 보니 뭔가 일주일 만에 엄청나게 성장하신 것 같은데요?! 코드 가독성도 좋아지고 고심하여 코드를 작성하신 게 느껴졌습니다! 🤝 이번주 과제도 고생하셨습니다!! 👍🏻
| }, | ||
| "dependencies": { | ||
| "@emotion/react": "^11.13.3", | ||
| "normalize.css": "^8.0.1", |
There was a problem hiding this comment.
오? normalize.css는 처음봐서 찾아보니 정규화를 시켜주고 다른 브라우저로 보더라도 일정한 디자인을 볼 수 있도록 해주기위해서 사용한다고 하는데 좋은거 알아갑니다!!!
| @@ -1,5 +1,85 @@ | |||
| /** @jsxImportSource @emotion/react */ | |||
| import { css } from '@emotion/react'; | |||
| import 'normalize.css'; | |||
There was a problem hiding this comment.
전역적으로 스타일을 적용하고 싶다면 Emotion의 Global 컴포넌트도 사용해 보세요!
참고 자료 - Emotion Global Styles
| const bodyStyle = css` | ||
| margin: 0; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| height: 100vh; | ||
| background-image: linear-gradient( | ||
| to bottom right, | ||
| rgb(247, 196, 218), | ||
| rgb(239, 239, 239) | ||
| ); | ||
| `; |
There was a problem hiding this comment.
스타일 코드는 컴포넌트(App) 바깥에 작성해 주시면 가독성이 더 좋아질 것 같아요 😀
export default function App() {
// 생략
}
const wrapper = css`
// 생략
`;There was a problem hiding this comment.
뺄지 말지 고민했던 부분 중 하나인데 확실하게 말씀해주셔서 좋아요ㅎ 당장 밖으로 빼겠습니다🫡
| // 초기 상태를 localStorage에서 불러옴 | ||
| const [todoList, setTodoList] = useState(() => { | ||
| const savedTodoList = localStorage.getItem('todoList'); | ||
| return savedTodoList ? JSON.parse(savedTodoList) : []; | ||
| }); |
There was a problem hiding this comment.
오 엄청 간결하면서도 동작이 잘 보여요!!
이름을 엄청 잘 지으시는 것 같어요
| }, [todoList]); | ||
|
|
||
| return ( | ||
| <div className="body" css={bodyStyle}> |
There was a problem hiding this comment.
클래스명을 부여하신 이유가 있으신가요?!
| const AddTodoList = todoList.concat({ | ||
| id: todoList.length, | ||
| text, | ||
| checked: false, | ||
| }); | ||
| setTodoList(AddTodoList); |
There was a problem hiding this comment.
concat 메서드 사용 좋습니다! spread 연산자도 활용해 봅시다!
| const AddTodoList = todoList.concat({ | |
| id: todoList.length, | |
| text, | |
| checked: false, | |
| }); | |
| setTodoList(AddTodoList); | |
| setTodoList(prev => [ | |
| ...prev, | |
| { | |
| id: todoList.length, | |
| text, | |
| checked: false, | |
| }, | |
| ]); |
| } | ||
|
|
||
| // props 값 검증 | ||
| InputBox.propTypes = { |
There was a problem hiding this comment.
나중에 타입스크립트도 잘하실 것 같아요 😉
| // 항목 삭제 | ||
| function onDelete(id) { | ||
| // 주어진 id와 일치하지 않는 항목들만 남김(일치하면 필터링 -> 해당 항목 삭제) | ||
| const updatedTodoList = todoList.filter((todoItem) => todoItem.id !== id); |
| <span | ||
| className="span" | ||
| // 완료 여부에 따라 스타일 변경 | ||
| css={todoItem.checked ? spanCheckedStyle : spanStyle} |
| @font-face { | ||
| font-family: 'LINESeedKR-Rg'; | ||
| src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_11-01@1.0/LINESeedKR-Rg.woff2') | ||
| format('woff2'); | ||
| font-weight: 400; | ||
| font-style: normal; | ||
| } |
There was a problem hiding this comment.
normalize.css를 비롯하여 이렇게 @font-face를 정의하는 부분도 글로벌 스타일로 적용해 보시면 좋을 것 같아요!
ongheong
left a comment
There was a problem hiding this comment.
안녕하세요 윤정님! 2주차 미션에서 윤정님의 코드 리뷰를 맡게 된 심여은입니다!
깔끔하고 귀여운 스타일과 props의 타입까지 체크하는 꼼꼼한 코드 잘 읽어 보았습니다! 저는 styled-component의 방식으로 작성했는데, 윤정님은 emotion의 css()를 잘 적용해 주신 것 같아요!
저도 이번에 state와 props 사용이 어렵다고 느꼈는데, 같이 공식문서 읽어보면서 성장해봐요~~!!
| <div className="container" css={containerStyle}> | ||
| <h2 className="title" css={mainTitleStyle}> |
There was a problem hiding this comment.
emotion을 잘 적용해 주셔서 코드가 매우 간결하네요!
| // + 버튼 클릭(form 제출) | ||
| function onClickButton() { | ||
| // 공백 입력 방지 | ||
| if (text.trim() === '') return; |
| todoList: PropTypes.arrayOf( | ||
| PropTypes.shape({ | ||
| id: PropTypes.number.isRequired, | ||
| text: PropTypes.string.isRequired, | ||
| }).isRequired | ||
| ), | ||
| setTodoList: PropTypes.func.isRequired, | ||
| }; |
There was a problem hiding this comment.
오 props 값을 이렇게 검증할 수 있군요! 새로 알아갑니다👀
| setTodoList(AddTodoList); | ||
|
|
||
| setText(''); // input 값 초기화 | ||
| inputRef.current.focus(); // 버튼 누른 후에도 input box에 자동 포커싱 |
There was a problem hiding this comment.
useRef를 이용해서 input에 포커스를 주는 부분 새롭게 알아갑니다👀👀
| &::-webkit-scrollbar { | ||
| // 스크롤바 모양 변경 | ||
| width: 4px; | ||
| } | ||
| &::-webkit-scrollbar-thumb { | ||
| border-radius: 2px; // 스크롤바 모서리 둥글게 | ||
| background: rgb(255, 238, 245); // 스크롤바 색상 변경 |
| const AddTodoList = todoList.concat({ | ||
| id: todoList.length, | ||
| text, | ||
| checked: false, | ||
| }); |
There was a problem hiding this comment.
TodoList 배열 안의 객체를 식별하는 id를 length로 주신 이유가 있을까요? 만약 id가 같다면 원하지 않는 다른 객체가 수정될 수 있을 것 같아요! Date.now()와 같이 중복되지 않는 값을 id에 할당하면 좋을 것 같습니다!
Sieonn
left a comment
There was a problem hiding this comment.
윤정님 그냥 화면만 봐도 깔끔 정갈 큐티입니다. 역시나 코드도 잘 정돈되어 있군요...!!!
제가 아이디어나 하고 싶은 기능을 쏟아내는 것은 잘하는데 깔끔하게 정리하고 효율적으로 사용하는것은 잘못하는데...많이 배우고 갑니다.. 최고...🩷
| }, | ||
| "dependencies": { | ||
| "@emotion/react": "^11.13.3", | ||
| "normalize.css": "^8.0.1", |
There was a problem hiding this comment.
오? normalize.css는 처음봐서 찾아보니 정규화를 시켜주고 다른 브라우저로 보더라도 일정한 디자인을 볼 수 있도록 해주기위해서 사용한다고 하는데 좋은거 알아갑니다!!!
| // 초기 상태를 localStorage에서 불러옴 | ||
| const [todoList, setTodoList] = useState(() => { | ||
| const savedTodoList = localStorage.getItem('todoList'); | ||
| return savedTodoList ? JSON.parse(savedTodoList) : []; | ||
| }); |
There was a problem hiding this comment.
오 엄청 간결하면서도 동작이 잘 보여요!!
이름을 엄청 잘 지으시는 것 같어요
|
|
||
| const [text, setText] = useState(''); | ||
| const [text, setText] = useState(''); // input에 입력한 값 | ||
| const inputRef = useRef(null); |
There was a problem hiding this comment.
저는 form을 사용하지 않아서 form을 사용했을 때 새로고침을 방지해야하는군요!! 배워갑니다!!!
| // + 버튼 클릭(form 제출) | ||
| function onClickButton() { | ||
| // 공백 입력 방지 | ||
| if (text.trim() === '') return; |
| @@ -79,8 +83,9 @@ export default function InputBox({ todoList, setTodoList }) { | |||
| ref={inputRef} | |||
| className="input-box" | |||
| placeholder="할일을 입력하세요" | |||
There was a problem hiding this comment.
이런 placeholder하나만으로도 이 사이트의 정체성을 보여주는 것 같아요. 🦖 친절한 사이트...
| margin: 3px 0px 3px 0px; | ||
| `; | ||
|
|
||
| const checkBoxStyle = css` |
There was a problem hiding this comment.
이렇게 체크박스까지 디테일을 놓치지 않는 것이 디자인적으로 완성도가 매우 높은 것 같습니다.👍🏻
안녕하세요! LG U+ 유레카 프론트엔드 1기 고윤정입니다.
React로 미션을 진행함에 있어 걱정이 많았는데 어찌저찌 끝냈네요..🤣 바닐라JS로 만들었던 투두리스트를 React로 다시 개발해보니 확실히 차이점이 눈에 보였습니다. React에 익숙하지 않았을 땐 HTML, CSS, JS 파일을 따로 나눠서 관리하는게 더 편하다고 생각했는데 이번 미션을 진행해보니 마크업과 렌더링 로직이 같은 위치에 있는게 더 관리하기 쉽고 편리하다는 걸 느꼈습니다. 여기서 사람들이 React를 사용하는 이유를 확 깨달았던 것 같아요!
공식문서를 읽으며 React와 더 친해지도록 하겠습니다 화이팅+_+ !
📎 알게 된 부분
css()함수 사용📎 개선하고 싶은 부분
📎 Key Questions
지난주 미션과 비교했을 때, React로 구현하는 과정에서 어떤 점이 더 편리하거나 복잡했나요?
React의 Virtual DOM(가상 돔)이란 무엇이고, 이를 사용했을 때의 장점은 무엇이 있나요?
React에서 state와 props는 무엇이고 어떻게 사용하나요?
setState()를 사용하여 값을 변경React에서 컴포넌트를 분리하는 기준은 무엇일까요?
📎 배포
https://jejukyj-react-todo.vercel.app/
