동적 컴포넌트를 위한 필수요소 Props, State에 대해 알아보자.
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
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로 치환된다.
defaultProps
다시 Basic 컴포넌트를 보면 this.props.lang이 있는데 부모 컴포넌트에서는 lang을 주지 않았다. 그런데도 JavaScript로 치환되었다.
<span>저는 {this.props.lang} 전문 {this.props.name}입니다!</span>
어떻게 이런 일이 일어날 수 있냐면 바로 defaultProps이기 때문이다. class 아랫부분을 보면 Basic.defaultProps = { ... }
로 lang을 Javascript로 만들었다. 만약 부모 컴포넌트에서 따로 lang 속성을 넘겨주지 않는다면 자동으로 defaultProps가 적용된다.
propTypes
Basic.propTypes = {
name: PropTypes.string.isRequired,
birth: PropTypes.number.isRequired,
lang: PropTypes.string,
};
propTypes는 name, birth,lang에 대한 내용이 들어있다. PropTypes 객체는 prop-types 패키지를 따로 설치해야 쓸 수 있다. 그리고 string, number, isRequired 등등이 있는데 바로 React의 props 자료형 검사법이다.
propTypes에 정의해두었으면 React가 해당 propTypes의 자료형과 일치하는지 검사한다. 다를 경우에는 에러를 내보낸다. name이 string으로 되어있는데, number이 들어왔을 경우 에러가 난다. isRequired는 필수라는 뜻. name과 birth 속성은 반드시 있어야한다는 것이 된다.
children
추가적으로 props에는 children이라는 것이 있다.
const Parent = () => {
return (
<div id="parent">{this.props.children}</div>
);
};
위와 같은 컴포넌트가 있다면 보통 이렇게만 사용하는데
<Parent>
<span>Hello</span>
</Parent>
위와 같이 내용물을 넣어줄 수 있습니다. 안에 넣은 span 태그는 this.props.children
과 연결됩니다. 따라서 결과적으로는 다음과 같이 됩니다.
<div id="parent"><span>Hello</span></div>
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
인 경우 다음 있다.그를 추가하라고 코딩되었습니다. 삼항 연산자처럼 React에서는 &&이나 ||를 사용하여 render 여부를 결정할 수 있다. if를 jsx 내에서 사용할 수 없기 때문에 다른 방법을 사용하는 것이다.
<button onClick={() => this.setState(() => ({ hidden: true }))}>숨기기</button>
위 버튼을 눌렀을 때 hidden statet를 true로 만들라고 되어있다. 일반 html과 달리 onclick이 아니라 onClick임을 주의!! 그리고 대소문자를 확실히 구분하기.
setState
잠깐 state 설정법을 보면 state를 바꾸려면 this.state.이름 = 바꿀 값;
잉렇게 하는 것이 아니라 this.setState((이전 상태) => ({ 이름: 바꿀 값 }));
이렇게 한다!! setState 메소드를 사용해야 함을 꼭 기억하기.
setState의 콜백 함수는 매개변수로 이전상태를 제공한다. 예를 들어 어떤 버튼을 눌렀을 때 hidden을 true에서 false로, false에서 true로 토글하고 싶다면 this.setState(prevState => ({ hidden: !prevState.hidden }))
하면 된다. 이러면 알아서 이전 상태와 반대로 값을 바꿔준다.
다시 본론으로 돌아가서 저 버튼을 누르면 1994년에 태어났습니다.라는 문장이 사란진다. 자동으로 반응하기 때문에 state를 조작만 하면 된다.