죽지도 않고 또 돌아온 계산기 미션입니다.
이번 미션은 우테코에서 React class Component를 구현하는 처음이자 마지막 미션이예요.
그리고 React를 본격적으로 시작하기 전에 맛보기 느낌의 온보딩 미션이였어요. 온보딩 미션 맞나.. 나만 진심이였지 또ㅠㅠ
그럼 계산기 미션 1단계에서 받은 피드백들을 살펴보러 가시죠!
HOC(High Order Component)는 컴포넌트 로직을 재사용하기 위한 React의 고급 기술입니다.
const AComponent = higherOrderComponent(BComponenet);
🤔 그런데 화살표 함수를 많이들 원해요. 왜 일까요?
불필요한 기능은 필요가 없으니까! (불필요한 기능들을 덜어내고 덜어냈기 때문에 화살표 함수를 사용하는 거예요.)
const StatelessComponent = props => <div> {props.name} </div>
👇 대표적인 useState
를 볼까요?
const [count,setCount] = useState(0);
리액트에서 가장 흔한 프로그래밍 패턴은 state를 가진 부모 컴포넌트가 있고 그 자식들이 props만 받고 state는 없는 컴포넌트들이 존재하는 경우입니다.
(포코의 생각 유도 질문!)
신호등을 예로 들어볼까요?
처음에는 신호등이 뭐 복잡할 이유가 없었죠.
💦 그런데 이제 보세요. 신호등도 복잡해졌죠.
신호등을 컴포넌트라고 생각하면 어떻게 확장될 수 있는지 생각해봅시다.
너무 javascript만 하는거 아니예요?
html 언어가 en으로 되어있는데... ko로 바꿔줍시다.
👉 프로젝트 내에서 내가 다루는 파일들을 이해하고 넘어갑시다.
setState({
...state,
prevNumber: selectedDigit,
})
---------vs---------
setState((prevState)=>({
firstNumber: prevState.firstNumber + value,
}));
이제 렌더링은 리액트가해요. 우린 권한이 없어😢😢
그러니 우리는 리액트의 렌더링 방식을 알아야해요.
// 1. 렌더링에 관련없이 사용됨
class Digits extends React.Component {
constructor(props) {
super(props);
// 2. 컴포넌트를 만들 때 내부 상태 정의
}
// 3. render에 필요한 정보, 함수, 라이프사이클 등을 정의
render() {
// 4. 렌더링될때마다 수행됨
return (
<div className="digits flex">
{[9, 8, 7, 6, 5, 4, 3, 2, 1, 0].map((digit) => (
<button
className="digit"
key={digit}
onClick={this.props.handleClickDigit}
>
{digit}
</button>
))} // list는 계속 반복되겠죠. 1번으로 옮기면 더 좋겠네요.
</div>
);
}
}
class Operators extends React.Component {
render() {
return (
<div className="operations subgrid">
{['/', 'X', '-', '+', '='].map((operator) => (
<button
className="operation"
key={operator}
onClick={this.props.handleClickOperator}
>
{operator}
</button>
))} // 마찬가지로 1번으로 옮길 것 같아요.
</div>
);
}
}
render() {
// 이걸로 해! 명령형 좋네요.
const result =
this.state.nextNumber === null ? this.state.prevNumber : this.state.nextNumber;
// 변수에 할당해서 사용 vs return 내부에서 사용
// 렌더링 순간마다 고유한 렌더링 값을 가진다 -> computedValue라고 합니다.
return <SomeCode>{this.state.isError
? '오류'
: `${this.state.firstOperand}
${this.state.operation ?? ''}
${this.state.secondOperand}`}</SomeCode>
}
render() {
// bad case... : render 메서드 안에서 해주고 있군요.
const { current } = this.state;
// 변경되지 않는데 이게 여기있네요. 바깥으로 보내죠?
const digits = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
const operators = ['/', 'X', '-', '+', '='];
return <SomeCode>{current === Infinity ? INFINITY_MESSAGE : current}</SomeCode>
}
왜 굳이 <> </> 를 써서라도 최상위 태그를 하나로 유지할까요?
Virtual DOM은 부모가 하나로 구성되면 효율적으로 찾을 수 있도록 구현되어 있거든요!
<button className="digit" data-number="9">
9
</button>
className: 리액트가 저렇게 하라해서 사실 웹 표준을 어긴거죠.
data-set: 웹표준을 지킨거죠.
⚠️ 하지만 dataSet은 비추한답니다!
❓ 왜 attribute를 props라 부를까요?
👇 attribute는 아래처럼 생성하죠.
<a id="mylink" href=""/>
document.getElementById("mylink").setAttribute("href", "")
👇 property는 아래처럼 생성하죠.
document.getElementById("mylink").href = ""
사실 attribute와 property는 모두 HTML의 일부입니다.
거기에 React는 추가 지원과 추상화를 제공합니다.
export default class Digit extends Component {
constructor(props) {
super(props);
this.state = { ...props };
}
}
class Keypad extends Component {
render() {
const { className, keyClassName, keypad, onClick } = this.props;
return (
<div className={className}>
{keypad.map((key) => (
<Button
key={key}
className={keyClassName}
onClick={onClick}
text={key.toString()} // react의 children을 쓰는게 나아요.
/>
))}
</div>
);
}
}
Keypad.propTypes = {
className: PropTypes.string,
keyClassName: PropTypes.string,
keypad: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.string),
PropTypes.arrayOf(PropTypes.number),
]),
onClick: PropTypes.func,
};
이번 리뷰어는 Vallista님!
🤔 이번 React를 CRA로 만들면서 기본적으로 생성되어지는 파일에 대해서 크게 생각 안하고 바로 이어서 코딩을 진행했는데 그런 안일한 행동을 하지 말아야겠다
라는 생각을 하게 되었어요.
😢 리뷰어님께서 왜 이렇게 했는지에 대해서 질문을 많이 주셨는데 제가 제대로 알고 적용한 부분들이 많이 없더라구요. (심지어 eslint도...!)
eslint
prettier
devDependencies vs dependencies
package.json의 각 설정들
manifest.json
robots.txt
픽셀 밀도
Number() vs parseInt
strict mode
화살표 함수를 쓰는 이유