React props와 state 알아보기
React에서 props와 state는 데이터를 다루는 개념입니다. 둘 다 JavaScript 객체이고 렌더링에 영향을 줍니다. props는 단방향 데이터 흐름의 리액트에서 상위에서 하위로의 데이터 전달을 위해 사용하고, state는 컴포넌트 내부에서 관리되는 데이터의 상태를 의미합니다. 좀 더 간단하게 설명하면 props는 함수에 전달하는 매개변수, state는 함수 내부에 선언된 변수 정도로 볼 수 있습니다.
1. props
props(properties)는 컴포넌트에 값을 전달할 때 사용합니다. 다음과 같이 App.js, Component.js를 만들고 실행해보면 Component.js에 전달된 props를 확인할 수 있습니다.
import React from 'react';
import Component from './Component';
function App() {
const name = 'React';
return (
<>
<Component name={name}/>
</>
);
}
export default App;
import React from 'react';
function Component(props) {
return (
<>
<div>{props.name}</div>
</>
);
}
export default Component;
1.1. defaultProps
defaultProps는 props 값을 따로 지정하지 않았을 때 설정하는 기본값입니다. 하위 컴포넌트에 전달되는 props가 없을 때 defaultProps를 설정하여 값을 지정할 수 있습니다.
import React from 'react';
import Component from './Component';
function App() {
return (
<>
<Component />
</>
);
}
export default App;
import React from 'react';
function Component(props) {
return (
<>
<div>{props.name}</div>
</>
);
}
Component.defaultProps = {
name: 'React'
};
export default Component;
1.2. children
props의 children을 사용하면 컴포넌트 태그 사이의 내용을 확인할 수 있습니다.
import React from 'react';
import Component from './Component';
function App() {
const name = 'React';
return (
<>
<Component name={name}>리액트</Component>
</>
);
}
export default App;
import React from 'react';
function Component(props) {
return (
<>
<div>{props.name}</div>
<div>{props.children}</div>
</>
);
}
export default Component;
1.3. props destructuring
ES6의 비구조화 할당을 사용하면 props 객체의 값을 추출하여 사용할 수 있습니다. 비구조화 할당은 함수형 컴포넌트에서 주로 사용합니다.
import React from 'react';
import Component from './Component';
function App() {
const name = 'React';
return (
<>
<Component name={name}>리액트</Component>
</>
);
}
export default App;
import React from 'react';
function Component(props) {
const {name, children} = props;
return (
<>
<div>{name}</div>
<div>{children}</div>
</>
);
}
export default Component;
1.4. propTypes
propTypes는 다음과 같이 컴포넌트 props의 타입이나 필수값을 지정할 때 사용합니다.
import React from 'react';
import Component from './Component';
function App() {
const name = 'React';
const version = 17;
return (
<>
<Component
name={name}
version={version}
>
리액트
</Component>
</>
);
}
export default App;
import React from 'react';
import PropTypes from 'prop-types';
function Component(props) {
const {name, version, children} = props;
return (
<>
<div>name: {name}</div>
<div>version: {version}</div>
<div>children: {children}</div>
</>
);
}
Component.propTypes = {
name: PropTypes.string.isRequired,
version: PropTypes.number
};
export default Component;
props가 propTypes에서 지정한 타입과 일치하지 않으면 브라우저에서 다음과 같이 에러가 발생합니다.
필수값으로 지정된 props를 전달하지 않을 경우에도 다음과 같이 에러가 발생합니다.
따라서 propTypes를 사용한 경우엔 타입과 필수로 설정된 props에 유의하여 사용하여야 합니다.
또한 propTypes에는 다양한 타입 지정이 가능한데 타입의 종류는 아래 링크에서 확인할 수 있습니다.
2. state
state는 컴포넌트 내부에서 관리되는 변경이 가능한 데이터를 의미합니다. props를 변경해주려면 부모 컴포넌트에서 변경해주어야 하고 전달받은 props는 읽기 전용으로만 사용됩니다. 하지만 state는 각각의 컴포넌트 내부에 존재하기 때문에 변경이 가능합니다.
리액트의 컴포넌트는 클래스형과 함수형으로 작성이 가능합니다. 그중에서 함수형 컴포넌트에서의 state 사용법에 대해 알아보고 정리하였습니다.
2.1. 함수형 컴포넌트의 useState
원래 리액트의 함수형 컴포넌트에서는 state를 사용할 수 없었습니다. 하지만 16.8 이후 버전에서 Hooks가 도입되었고 Hooks의 useState를 이용하여 함수형 컴포넌트에서도 state를 사용할 수 있게 되었습니다.
useState의 사용을 위해서는 배열의 비구조화 할당이 필요합니다. 아래의 두 코드는 동일한 실행 결과를 나타냅니다. 비구조화 할당을 이용하면 객체나 배열 안의 값을 쉽게 추출하여 사용할 수 있습니다.
const array = [1, 2];
const arr1 = array[0];
const arr2 = array[1];
const array = [1, 2];
const [arr1, arr2] = array;
useState의 사용을 위해서는 다음과 같이 작성해줄 수 있습니다. useState 함수의 파라미터로는 초기화할 값을 넣어줍니다. 배열의 첫번째 원소는 현재 상태를 나타내고 두번째 원소는 상태를 변경해주는 역할을 합니다. 좀 더 쉽게 이해하고자한다면 getter, setter 함수로 보면 되겠습니다.
const [value, setValue] = useState(0);
다음과 같이 예제를 작성해줍니다.
import React from 'react';
import Component from './Component';
function App() {
return (
<>
<Component/>
</>
);
}
export default App;
import React, { useState } from 'react';
function Component() {
const [value, setValue] = useState(0);
const onIncrease = () => {
setValue(prevValue => prevValue + 1);
}
const onDecrease = () => {
setValue(prevValue => prevValue - 1);
}
return (
<>
<h1>value: {value}</h1>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</>
);
}
export default Component;
실행해보면 '+' 또는 '-' 버튼을 클릭할 때마다 useState의 setter 함수가 호출되어 값이 변경되는 것을 확인할 수 있습니다.
2.2. state 사용시 주의사항
useState를 사용할 때 다음과 같은 코드는 잘못된 코드입니다.
const targetObj = {
a: 1,
b: 2
};
const [obj, setObj] = useState(targetObj);
obj.a = 10;
배열이나 객체의 값을 변경할 때는 사본을 만들고 사본을 변경한 뒤에 setter 함수를 이용하여 업데이트 해주어야 합니다. 다음과 같이 객체의 사본을 만들 때는 spread 연산자를 사용하고 배열의 사본을 만들 때는 배열의 내장 함수를 사용해줍니다.
const object = {
a: 1,
b: 2,
c: 3
};
const nextObject = { ...object, a: 10 }; // 사본을 만들어서 a의 값을 변경
const array = [
{id: 1, checked: false},
{id: 2, checked: false},
{id: 3, checked: false}
];
const nextArray1 = array.concat({ id: 4, checked: false });
const nextArray2 = nextArray1.map(item => (item.id === 1 ? { ...item, checked: true} : item)); // id가 1인 항목의 checked 값을 false로 변경
이상으로 React props와 state에 대해 알아봤습니다.
※ Reference
- reactjs.org, Component State, https://reactjs.org/docs/faq-state.html
- react.vlpt.us, 5. props 를 통해 컴포넌트에게 값 전달하기, https://react.vlpt.us/basic/05-props.html
- react.vlpt.us, 7. useState 를 통해 컴포넌트에서 바뀌는 값 관리하기, https://react.vlpt.us/basic/07-useState.html
- velopert.com, 누구든지 하는 리액트 4편: props 와 state, https://velopert.com/3629
- studyingych.tistory.com, React Props, State 이해 및 사용법, https://studyingych.tistory.com/52
- trustyoo86.github.io, React 기억법(4) - React 필수요소 props, state, https://trustyoo86.github.io/react/2017/11/18/props-state-react.html
- 『리액트를 다루는 기술』 길벗(2019) 김민준 지음, 3장 컴포넌트 (p85 ~ p117)