안녕하세요. 이번 시간에는 동적 컴포넌트를 위한 필수요소 Props와 State에 대해 알아보겠습니다! 일단 지난 시간에 사용한 Basic 컴포넌트를 재사용하겠습니다! 조금 많이 수정했으니 찬찬히 살펴보세요.
import React, { Component } from 'react';
import PropTypes from 'prop-types'; // 패키지 추가
class Basic extends Component {
constructor(props) {
super(props);
this.state = {
hidden: false,
};
}
render() {
return (
<div>
<span>저는 {this.props.lang} 전문 {this.props.name}입니다!</span>
{!this.state.hidden && <span>{this.props.birth}년에 태어났습니다.</span>}
<button onClick={() => this.setState(() => ({ hidden: true }))}>숨기기</button>
</div>
);
}
}
Basic.propTypes = {
name: PropTypes.string.isRequired,
birth: PropTypes.number.isRequired,
lang: PropTypes.string,
};
Basic.defaultProps = {
lang: 'Javascript',
};
export default Basic;
이번 시간에 배울 props와 state를 추가해보았습니다. 일단 소개부터 하겠습니다!
Props
props는 부모 컴포넌트로부터 물려받는 속성입니다. 이를 통해 부모 컴포넌트와 소통할 수도 있죠. 부모 컴포넌트에서 전달하는 props가 바뀌면 자동으로 업데이트됩니다. render.js에서 다음과 같이 바꿉니다.
render(<Basic name="Zero" birth={1994} />, document.getElementById('root'));
이전 시간과는 달리, 부모 컴포넌트에 Basic 컴포넌트를 부착하는 부분에서 추가적인 속성을 주었습니다. name 속성의 값은 "Zero"로, birth 속성의 값은 1994로 주었네요. 바로 이게 props입니다. 컴포넌트 내에서 this.props.속성이름
으로 접근가능합니다. 위의 Basic 컴포넌트를 다시 보면, this.props.name
과 this.props.birth
가 있죠? 이 부분이 각각 Zero와 1994로 치환됩니다.
Zero는 따옴표로 감쌌는데 birth는 { }로 감쌌습니다. props는 html처럼 기본이 문자열이기 때문에 다른 자료형을 전달하려면 { } 안에 넣어야 합니다.
defaultProps
다시 Basic 컴포넌트를 보면, this.props.lang
이 있는데 부모 컴포넌트에서는 lang을 주지 않았습니다. 그런데도 Javascript로 치환되었습니다.
<span>저는 {this.props.lang} 전문 {this.props.name}입니다!</span>
어떻게 이런 일이 일어날 수 있을까요? 바로 defaultProps이기 때문입니다. class 아랫부분을 보면 Basic.defaultProps = { ... }
로 lang을 Javascript로 만들었습니다. 만약 부모 컴포넌트에서 따로 lang 속성을 넘겨주지 않는다면 자동으로 defaultProps가 적용됩니다.
propTypes
npm install prop-types
prop-types 패키지를 설치합니다.
Basic.propTypes = {
name: PropTypes.string.isRequired,
birth: PropTypes.number.isRequired,
lang: PropTypes.string,
};
그 위에 설명하지 않은 propTypes에 대해서 알려드리겠습니다. propTypes에 보면 name, birth, lang에 대한 내용이 들어있습니다. PropTypes 객체는 prop-types 패키지를 따로 설치해야 쓸 수 있습니다. 그리고 string, number, isRequired 등등이 나와 있네요. 바로 React의 props 자료형 검사법입니다.
propTypes에 정의해두었으면 React가 해당 props가 propTypes의 자료형과 일치하는지 검사합니다. 다를 경우 에러를 내보내고요. name이 string으로 되어있는데, number이 들어왔을 경우 에러가 나는 거죠. isRequired는 필수라는 뜻입니다. name과 birth 속성은 반드시 있어야 한다는 것이죠. 자료형도 일치해야 하고, 필수적으로 넣어주어야 합니다. isRequired가 붙지 않으면 선택적이라는 뜻입니다. 다양한 종류의 propTypes가 있는데 여기에서 확인하세요.
children
추가적으로 props에는 children 이라는 것이 있습니다.
const Parent = () => {
return (
<div id="parent">{this.props.children}</div>
);
};
위와 같은 컴포넌트가 있다면 보통 <Parent />
이렇게만 사용하는데요.
<Parent>
<span>Hello</span>
</Parent>
위와 같이 내용물을 넣어줄 수 있습니다. 안에 넣은 span 태그는 this.props.children
과 연결됩니다. 따라서 결과적으로는 다음과 같이 됩니다.
<div id="parent"><span>Hello</span></div>
State
만약 hooks에 추가된 useState를 배워보려고 하시는 거라면 이 링크 를 클릭해주세요! hooks를 배우더라도 class 컴포넌트의 state 사용법도 알아두시는 게 좋습니다.
constructor() {
this.state = {
hidden: false,
};
}
constructor 안을 보면 state라는 것이 보입니다. state는 컴포넌트가 만들어질 때 가장 먼저 설정되는 것이기 때문에 constructor 안에 적어줍니다.
state는 해당 컴포넌트에만 적용되는 상태입니다. 예를 들면, 내비게이션 메뉴를 켜고 끌 때 state에 on/off 상태를 등록해둘 수 있습니다. 역시 props처럼 자동으로 업데이트되어 편합니다.
위의 예를 보시면 처음에 state에 hidden이 기본으로 설정된 것을 보실 수 있습니다. 그리고
{!this.state.hidden && <span>{this.props.birth}년에 태어났습니다.</span>}
에서 this.state.hidden === false
인 경우 다음 span 태그를 추가하라고 코딩되어있습니다. 삼항 연산자처럼 React에서는 &&이나 ||를 사용하여 render 여부를 결정할 수 있습니다. if를 jsx 내에서 사용할 수 없기 때문에 다른 방법을 사용하는 겁니다.
<button onClick={() => this.setState(() => ({ hidden: true }))}>숨기기</button>
위 버튼은 눌렀을 때 hidden state를 true로 만들라고 되어있네요. 일반 html과 달리 onclick이 아니라 onClick임을 주의해주세요. 대소문자를 확실하게 구분하셔야 합니다.
보통 어떤 것을 state로 만들까요? 저는 화면이 바뀌는 것에 관한 데이터을 state로 만들어둡니다. hidden state에 따라 span 태그가 보여질지 말지가 결정됩니다. state를 바꾸면 알아서 화면이 다시 그려지는 것이죠. 따라서 화면을 다시 그려야하는 상황에서, 다시 그려야할지 판단하는 데이터가 state가 됩니다. 핵심은 react에서는 화면을 변경(dom 조작)하는 것이 아니라 데이터를 변경해야 된다는 것입니다. 화면은 데이터에 따라서 알아서 바뀌는 것이고요.
state들은 다른 컴포넌트에 props를 통해 넘겨줄 수 있습니다.
setState
잠깐 state 설정법에 대해서 알아보자면, state를 바꾸려면 this.state.이름 = 바꿀 값
; 이렇게 하는 것이 아니라, this.setState((이전 상태) => ({ 이름: 바꿀 값 }));
이렇게 하는 겁니다. setState 메소드를 사용해야 함을 꼭 기억하세요.
setState의 콜백 함수는 매개변수로 이전 상태를 제공합니다. 예를 들어 어떤 버튼을 눌렀을 때 hidden을 true에서 false로, false에서 true로 토글하고 싶다면 this.setState(prevState => ({ hidden: !prevState.hidden }))
하면 됩니다. 알아서 이전 상태와 반대로 값을 바꿔줍니다.
다시 본론으로 돌아가서 저 버튼을 누르면 바로 1994년에 태어났습니다. 라는 문장이 사라집니다! 자동으로 반응하기 때문에 state를 조작만 하면 됩니다.
지금까지 배운 props와 state로 동적 컴포넌트를 만들어보세요. 다음 시간에는 React 이벤트 바인딩에 대해서 살펴보겠습니다!