-
Notifications
You must be signed in to change notification settings - Fork 34
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
[1단계 - 행운의 로또미션] 하루(김하루) 미션 제출합니다. #8
Conversation
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: JUNMO HAN <wnsah052@naver.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
src/components/PurchaseLotto.js
Outdated
</div> | ||
<section className={`display-section ${this.state.isToggled && 'toggle'}`}> | ||
{this.props.lottoBundle.map((v, i) => ( | ||
<Lotto numbers={v} key={String.fromCharCode(97 + i)} /> |
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.
질문드립니다! 🙋🏻♀️ - 배열의 key값
index
가 아닌 어떤 key
를 사용할 수 있을지 고민스러웠습니다...🤔
페어와 고민하다가0, 1, 2, ...
를 'a', 'b', 'c', ...
로 변환해봤는데 괜찮은 방법일지 혹은 추천해주시고 싶으신 더 일반적인(?) 방법이 있을지 궁금합니다.
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.
'key를 왜 넣어줘야 하는가?' 를 먼저 생각해보셔도 좋을 것 같네요?!
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.
리액트에서 리스트를 만들 때 고유한 key를 설정하도록 강제하는 이유는 배열의 요소 추가, 수정, 삭제에 효율적으로 대응하기 위함으로 알고 있습니다.
- 효율성 측면
- 예시: [a b c] 리스트에서 a를 삭제하여 [b c] 를 렌더할 경우,
- 문제: key값을 주지 않으면 a자리에 b를, b자리에 c를, c자리에는 아무것도 렌더하지 않는 번거로운 작업이 필요합니다.
(key값을 주면 [a b c]에서 바로 a만 key값으로 잡아와서 빠르게 삭제할 수 있습니다.)
- 데이터 맵핑 측면
- 예시: [a b c] 리스트에서 a앞에 z를 추가하여 [z a b c] 를 렌더할 경우,
- 문제: key값을 주지 않으면 리액트는 index를 default key값으로 활용하는데 이는 a(기존 index 0)가 가지고 있던 데이터가 z(새로운 index 0)에 맵핑되어 버립니다.(참고한 글)
두 가지 측면을 모두 생각해보았을 때 고유한 key값을 가져야 한다
는 의미는 배열 내 형제끼리 중복되지만 않으면 된다
라는 것 뿐만 아니라, 리렌더 되었을 때도 자신만의 고유한 key를 유지할 있어야 한다
는 의미로 이해했습니다. 🤔 제가 이해한 내용이 맞다면, index를 순차적으로 변환해서 'a', 'b', 'c', ...
를 key값으로 주는 방식은 위의 데이터 맵핑이 꼬이는 문제를 전혀 해결할 수 없다고 생각됩니다. 따라서 리액트에서 필요로하는 key값을 주려면 nano id와 같은 id 생성기를 이용해야겠다고 생각했습니다.
그런데 같은 글에 따르면, 지금 제 경우처럼 리스트가 변하지 않고 정적일 것이 보장(재정렬, 필터되지 않음)되는 경우인데 딱히 쓸만한 id를 가진 것도 아닌 경우에는 굳이굳이 id를 생성하기 보다는 index를 key로 사용해도 좋다고 하고 있습니다...! 제가 생각해도 key가 꼭 필요한 상황이 아니어서 이런 경우에는 key값을 생략하려고 합니다..!
혹시 제가 잘못 생각한, 잘못 알고 있는 부분이 있다면 지적해주시면 감사하겠습니다 🙇🏻♀️
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.
수고하셨습니다~ 코멘트 몇개 남겼어요!
기존 로또 프로젝트를 옮겨오지 말고 리액트 관점에 맞춰서 재정의하는 것이 더 좋을 것 같다는 생각이 들어요.
컴포넌트는 무엇인지, 어떤 단위로 나누어야 하는지도 같이 고민해봐요!
리뷰어님 안녕하세요! 코멘트 남겨주신 것 보고 리팩토링 진행해봤습니다...! 💪 컴포넌트 설계 ✍🏻✨컴포넌트✨는 비단 리액트에서뿐만 아니라 프로그래밍 전반에서 이번 PR 에서 총 4개의 컴포넌트를 만들었는데, 이 컴포넌트 들은 최상위 App 컴포넌트를 쪼개기 위한 재사용 가능한 컴포넌트를 만들자는 목적으로 리팩토링을 시작했습니다. 🚀 최상위 컴포넌트에 가까울수록 도메인 로직이 많이 들어가서 재사용할 수 있게 만들기 어렵지만, 하위 컴포넌트로 내려오면 좀 더 재사용 가능한 컴포넌트를 뽑아내기 쉬울 것이라고 생각했습니다. 그래서 우선,
한편, 앱 내에서 여러 컴포넌트에 걸쳐 사용되고 있다면 도메인과 연관이 있더라도 수십 개의 파일을 수정하면서 나름 대공사를 거쳤는데, 목적대로 재사용성이 높아진건지 잘 모르겠...습니다...🥲 분명 이전의 4개의 왕컴포넌트 보다는 낫겠지만... 한번 보시고 피드백 주시면 감사하겠습니다...!! 🙇🏻♀️🙇🏻♀️
|
📌 리뷰반영 요약표
|
export default class TwoDigitBall extends Component { | ||
render() { | ||
const { number, className } = this.props; | ||
const numberText = number < 10 ? `0${number}` : number; |
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.
앗 내장 메서드가 있었군요...! 🥺 바로 적용해보겠습니당!! 감사합니다..!! 🙏
const { number, className } = this.props; | ||
const numberText = number < 10 ? `0${number}` : number; | ||
|
||
return <span className={`TwoDigitBall ${className}`}>{numberText}</span>; |
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.
오와오!!!!! 대박스 바로 설치해서 적용해보겠습니다! 제이비님 꿀벌이셨군요,,, 꿀팁에서 꿀이 쥬르르...🍯💙
Co-authored-by: Jbee <ljyhanll@gmail.com>
Co-authored-by: Jbee <ljyhanll@gmail.com>
<p className="ResultSummary__profit"> | ||
<span className="ResultSummary__description">당첨 금액</span> | ||
<span className="ResultSummary__value">{profit}원</span> | ||
</p> |
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.
저라면 요 단위를 컴포넌트화 해볼 것 같아요!
Record
라는 이름으로요!
ResultSummary
라는 컴포넌트가 재사용될까요? 🤔
<p className="ResultSummary__profit"> | |
<span className="ResultSummary__description">당첨 금액</span> | |
<span className="ResultSummary__value">{profit}원</span> | |
</p> | |
function Record() { | |
return ( | |
<p className="record"> | |
<span className="record-label">{label}</span> | |
<span className="record-value">{children}</span> | |
</p> | |
) | |
} |
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.
오어... 이거였습니다... 제가 하고싶었던게,,,🤩 이렇게 누가봐도 재사용할 수 있을 것 같은 컴포넌트였는데... 현실은...🥲ResultSummary
는 상위 컨테이너가 장황해져서 쪼개려는 목적으로 분리하게 되었습니다,,, 위에 공유해주셨던 챠크라의 컴포넌트 천천히 살펴보고, 단순히 쪼개는 것보다 재사용성을 좀 더 고민하면서 이렇게 재사용 가능한 컴포넌트를 늘려보겠습니다!! 정말정말 시야가 트이는 느낌이에요! 감사합니다~🙇🏻♀️😆🙇🏻♀️
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.
1단계 제한사항이 클래스 컴포넌트를 사용하는 것이라서 클래스 컴포넌트로 반영해보았습니다..!
📌 관련커밋: 61ff42a
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.
앗 코멘트를 이제봤네요...! 높은 응집도 + 낮은 결합도
유념해서 도전해보겠습니다!! 🚀🚀🚀🚀 감사합니다! 💙
Co-authored-by: Jbee <ljyhanll@gmail.com>
const { className, children, ...props } = this.props; | ||
const buttonClass = cx({ | ||
Button: true, | ||
[`${className}`]: true, | ||
}); | ||
|
||
return ( | ||
<button className={buttonClass} {...props}> | ||
{children} | ||
</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.
- children 그대로 넘겨주면 되겠는데요?
- className에 아무 것도 안 넘긴다면?
+) classname엔 대문자가 좀 어색하네요 ㅎㅎ
const { className, children, ...props } = this.props; | |
const buttonClass = cx({ | |
Button: true, | |
[`${className}`]: true, | |
}); | |
return ( | |
<button className={buttonClass} {...props}> | |
{children} | |
</button> | |
const { className, ...props } = this.props; | |
const buttonClass = cx(className, 'Button'); | |
return ( | |
<button className={buttonClass} {...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.
앗 조건부 아니고 항상 넣어줄거면 심플하게 인자로 넣어주면 되는거였군요! 리드미에 Syntax 다시 읽고왔습니당ㅎㅎ 감사합니다!
classNames('foo', 'foo', 'bar'); // => 'foo bar'
classNames('foo', { foo: false, bar: true }); // => 'bar'
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.
- children 그대로 넘겨주면 되겠는데요?
말씀해주신 것처럼 children
을 ...props
에 한꺼번에 넣을 경우 JSX가 어떻게 처리되는지 아직 머릿 속에 잘 안그려져서 Babel에 적어봤습니다..!
// children을 children 자리에 직접 넣어주는 경우
<button className={buttonClass} {...props}>
{children}
</button>
// 트랜스파일 후
export default class Button extends Component {
render() {
const { className, children, ...props } = this.props;
const buttonClass = cx(className, "Button");
return /*#__PURE__*/ React.createElement(
"button",
_extends(
{
className: buttonClass
},
props
),
children // 👈 요기 들어감
);
}
}
// children을 ...props에 포함시켜넣거나 props와 같은 위계(?)에서 넘겨주는 경우
<button className={buttonClass} children={children} {...props} />
// 트랜스파일 후
export default class Button extends Component {
render() {
const { className, children, ...props } = this.props;
const buttonClass = cx(className, "Button");
return /*#__PURE__*/ React.createElement(
"button",
_extends(
{
className: buttonClass,
children: children // 👈 요기 들어감
},
props
)
);
}
}
두 경우에 트랜스파일링 후 children이 들어가는 위치가 다르게 보이고, React.createElement API에서 세번째 인자를 children로 넣어주고 있어서 두번째 인자에 한번에 ...props
로 보내도 괜찮을까 싶었는데 실행시켜 보니까 잘되네요,,,,?,,,,,👉👈
요것이 이해가 안되는 건 제가 JS문법 기초가 부족해서일까요,,,🥲 어떻게 이해하면 좋을지 조언해주시면 매우매우 감사하겠습니다,,, 🙏
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.
- className에 아무 것도 안 넘긴다면?
className에 아무것도 안넘긴다면 undefined
: true가 되고 있었군요...! 수정해주신대로 하면 classnames가 알아서 처리해주니 문제 없겠네요! 감사합니다 😆
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.
+) classname엔 대문자가 좀 어색하네요 ㅎㅎ
classnames
은 정말 별 생각없이(...) 제 VS Code에 설치된 코드 스펠링 체크해주는 익스텐션 cspell
에서 밑줄 띄워줘서 classNames
으로 적었었는데요,,,! 필요할 경우 user dictionary
에 추가하거나 cspell.json
에서 설정을 작성자가 필요한대로 바꿀 수 있다는 사실을 알게되었습니다! (참고문서) classnames
외에도 추가할 단어들이 있을 것 같고, 이 설정 파일도 push해놓는게 좋을 것 같아서 cspell.json에서 관리해보려고 합니당! 에디터에 cspell
때문에 PROBLEM 몇십 개 줄줄이 뜨곤 했는데...(못본 척했지만...🥲) 이제 없앨 수 있게되었네요~~~😆
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.
수고하셨어요!ㅎㅎ
일부러 빡세게 리뷰했는데, 너무 빡빡했다면 피드백 해주세요!
코멘트 하나 살짝 추가해봤어요~ (https://github.com/woowacourse/react-lotto/pull/8/files#r615501370)
Jbee님, 안녕하세요!
오랜만에 인사드리는 🙋🏻♀️ 하루(@365kim) 입니다.
지난 레벨1 때도 로또 리뷰를 도와주셨었는데 요번에도 로또 미션으로 인사드리게 되었네요 ㅎㅎ
저는 주모(@jum0)과 함께 페어프로그래밍을 진행했습니다.
🎟 1단계 데모 페이지
✅ 구현 기능 목록
💪 새롭게 시도한 부분
💪 UX/UI고려사항
리액트 공식문서를 채 다 못 읽은 채 미션을 진행하고 있어서 많이 부족한 상태지만, 크고 작은 개선사항 코멘트로 전해주시면 열심히 배우고 또 열심히 개선해보겠습니다..!!! 🙇🏻♀️🙇🏻♀️
감사합니다 😆