먼저 BoilingVerdict
라는 이름의 컴포넌트부터 만들어봅시다. 이 컴포넌트는 섭씨온도를 의미하는 celsius
prop를 받아서 이 온도가 물이 끓기에 충분한지 여부를 출력합니다.
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>; }
return <p>The water would not boil.</p>;}
그 다음으로 Calculator
라는 컴포넌트를 만들어보겠습니다. 이 컴포넌트는 온도를 입력할 수 있는 <input>
을 렌더링하고 그 값을 this.state.temperature
에 저장합니다.
또한 현재 입력값에 대한 BoilingVerdict
컴포넌트를 렌더링합니다.
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''}; }
handleChange(e) {
this.setState({temperature: e.target.value}); }
render() {
const temperature = this.state.temperature; return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature} onChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
이제 Calculator
가 분리된 두 개의 온도 입력 필드를 렌더링하도록 변경할 수 있습니다.
class Calculator extends React.Component {
render() {
return (
<div>
<TemperatureInput scale="c" /><TemperatureInput scale="f" />
</div>
);
}
}
현재는 두 TemperatureInput
컴포넌트가 각각의 입력값을 각자의 state에 독립적으로 저장하고 있습니다.
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''}; }
handleChange(e) {
this.setState({temperature: e.target.value}); }
render() {
const temperature = this.state.temperature; // ...
그러나 우리는 두 입력값이 서로의 것과 동기화된 상태로 있길 원합니다. 섭씨온도 입력값을 변경할 경우 화씨온도 입력값 역시 변환된 온도를 반영할 수 있어야 하며, 그 반대의 경우에도 마찬가지여야 합니다.
React에서 state를 공유하는 일은 그 값을 필요로 하는 컴포넌트 간의 가장 가까운 공통 조상으로 state를 끌어올림으로써 이뤄낼 수 있습니다. 이렇게 하는 방법을 “state 끌어올리기”라고 부릅니다. 이제 TemperatureInput
이 개별적으로 가지고 있던 지역 state를 지우는 대신 Calculator
로 그 값을 옮겨놓을 것입니다.
Calculator
가 공유될 state를 소유하고 있으면 이 컴포넌트는 두 입력 필드의 현재 온도에 대한 “진리의 원천(source of truth)“이 됩니다. 이를 통해 두 입력 필드가 서로 간에 일관된 값을 유지하도록 만들 수 있습니다. 두 TemperatureInput
컴포넌트의 props가 같은 부모인 Calculator
로부터 전달되기 때문에, 두 입력 필드는 항상 동기화된 상태를 유지할 수 있게 됩니다.
어떻게 동작하는지 차근차근 살펴봅시다.
우선, TemperatureInput
컴포넌트에서 this.state.temperature
를 this.props.temperature
로 대체할 것입니다. 지금은 this.props.temperature
가 이미 존재한다고 가정해봅시다. 나중에는 이 값을 Calculator
로부터 건네야 할 것입니다.
render() {
// Before: const temperature = this.state.temperature;
const temperature = this.props.temperature; // ...
props는 읽기 전용입니다. temperature
가 지역 state였을 때는 그 값을 변경하기 위해서 그저 TemperatureInput
의 this.setState()
를 호출하는 걸로 충분했습니다. 그러나 이제 temperature
가 부모로부터 prop로 전달되기 때문에 TemperatureInput
은 그 값을 제어할 능력이 없습니다.
React에서는 보통 이 문제를 컴포넌트를 “제어” 가능하게 만드는 방식으로 해결합니다. DOM <input>
이 value
와 onChange
prop를 건네받는 것과 비슷한 방식으로, 사용자 정의된 TemperatureInput
역시 temperature
와 onTemperatureChange
props를 자신의 부모인 Calculator
로부터 건네받을 수 있습니다.
이제 TemperatureInput
에서 온도를 갱신하고 싶으면 this.props.onTemperatureChange
를 호출하면 됩니다.