state와 props는 리액트의 가장 중요한 개념들 중 기본 핵심이라고 할 수 있다. 지난 포스트에서 간단히 props에 대해 언급을 하고 지나갔는데 복습차원에서 다시 한번 정리하고, state 개념을 살펴보자.
props는 properties를 의미하며 부모 컴포넌트에서 자식 컴포넌트로 데이터, 함수 같은 props를 컴포넌트에 주입함으로써 데이터를 전달하고 컴포넌트를 조작할 수 있다. 아래 예제 형태를 보면 이해하기 쉬울 것이다.
import React, { component } from 'react';
class Test extends Component {
render(){
return (
<div className="Test">
<SubTest title="subtest" />
</div>
)
}
}
export default Test();
...
class SubTest extends Component {
render(){
return (
<div>{this.props.title}</div>
)
}
}
export default SubTest();
import React from 'react';
export default function Test() {
return (
<div className="Test">
<SubTest title="subtest" />
</div>
)
}
...
export default function SubTest({title}) {
return (
<div>{title}</div>
)
}
한편, 어떤 상황에서는 props 값을 일부러 비우거나 기본값을 설정해야 할 수가 있다. 이 때는 defaultProps라는 것을 사용하며 예시는 아래와 같다.
import React, { component } from 'react';
class Test extends Component {
render(){
return (
<div className="Test">
<SubTest />
</div>
)
}
}
export default Test;
...
class SubTest extends Component {
static defaultProps = {
title: 'subtest'
}
render(){
return (
<div>{this.props.title}</div>
)
}
}
export default SubTest;
하나 주의해야 할 점은 props는 'Read Only' 이기 때문에 전달 받은 props의 값을 자식 컴포넌트에서 직접적으로 변경하는 것은 불가능하다는 것이다.
우리말로 "상태"로 번역되는 state는 데이터를 동적으로 변경해야 할 때 사용하는 것으로 일종의 컴포넌트 부품이다. props가 읽기 전용인데 비해 state는 쓰기까지 가능한 것이 특징이며, state로 정의한 값이나 함수는 변경이 가능하다.
원래 이 state는 react가 초기에 나왔을 때 널리 사용된 클래스형 컴포넌트에만 존재했었다. 그러다 함수 컴포넌트가 등장했는데, 초기 함수 컴포넌트는 이 state를 사용하지 못한다는 치명적인 단점을 안고 있었다. React v16.8+ 이후 React Hooks가 나옴에 따라 함수 컴포넌트에서도 이 state가 사용 가능하게 되었고, state 값을 변경 해주는 메서드는 클래스형과 함수형 각각 'setState()'와 'useState()'로 대응되었다.
이 state를 변경할 때 re-rendering이 일어난다. setState의 경우 값을 객체로 전달해주어야 하며, 객체의 객체까지 확인/업데이트는 하지 못한다.
import React, { component } from 'react';
class Test extends Component {
constructor(props){
// state 값 초기화를 원한다면
super(props);
this.state = {
title: 'subtest'
}
}
render(){
return (
<div className="Test">
<SubTest title={this.state.title}
onClick={function(){
this.setState({
title: "Clicked"
});
}.bind(this)}/>
</div>
)
}
}
export default Test;
...
class SubTest extends Component {
render(){
return (
<button onClick={function(e){
e.preventDefault();
console.log('clicked');
}.bind(this)}
>{this.props.title}</button>
)
}
}
export default SubTest;
import React, { useState } from 'react';
export default function Test() {
const [title, setTitle] = useState('subtest');
return (
<div className="Test">
<SubTest title={title} onClick={
() => setTitle('Clicked')
}/>
</div>
)
}
...
export default function SubTest({title}) {
return (
<button onClick={(e) =>{
e.preventDefault();
return console.log('clicked');
}}>{title}</button>
)
}
React의 props와 state를 간단하게 살펴보았으므로 다음 포스트에서 TODO 앱의 CRUD 기능을 props와 state로 완성 시켜보자.