공유된 state
자식 컴포넌트들이 가장 가까운 공통된 부모 컴포넌트의 state를 공유하여 사용하는 것
(== 하위 컴포넌트가 공통된 상위 컴포넌트의 state를 공유하여 사용하는 것)
특정 컴포넌트의 state에 있는 데이터를 여러 개의 하위 컴포넌트에서 공통적으로 사용하는 경우
![]() | ![]() |
|---|
왼쪽 그림의 경우, 자식 컴포넌트가 각각 값을 가지고 있을 필요 없이 부모 컴포넌트의 state에 있는 값에 연산(x2, x3…)을 해주면 된다.
오른쪽 그림의 경우도, 자식 컴포넌트가 각각 온도값을 가지고 있을 필요 없이 부모 컴포넌트의 온도값을 변환해주면 된다.
function BoilingVerdict(props){
if(props.celsius >= 100){
return <p>물이 끓습니다.</p>;
}
return <p>물이 끓지 않습니다..</p>;
}
function Calculator(props){
const [temperature, setTemperature] = useState('');
const handleChangeTemp = (event) => {
setTemperature(event.target.value);
}
return (
<fieldset>
<legend>섭씨 온도를 입력하세요:</legend>
<input value = {temperature} onChange = {handleChangeTemp}/>
<BoilingVerdict
celsius = {parseFloat(temperature)} />
</fieldset>
)
}
const scaleNames = {
c:'섭씨',
f:'화씨'
};
function TemperatureInput(props){
const [temperature, setTemperature] = useState('');
const handleChange = (event) =>{
setTemperature(event.target.value);
}
return (
<fieldset>
<legend>
온도를 입력해주세요(단위:{scaleNames[props.scale]}):
</legend>
<input value = {temperature} onChange = {setTemperature}/>
</fieldset>
);
}
function Calculator(props){
return(
<div>
<TemperatureInput scale = "c" />
<TemperatureInput scale = "f" />
</div>
);
}
⚠️ 사용자가 입력하는 온도값이 TemperatureInput의 state에 저장되기 때문에 섭씨온도와 화씨온도 값을 따로 입력받으면 2개의 값이 다를 수 있음.
2개의 TemperatureInput은 독립된 element이므로, 입력값이 각각의 state에 저장됨 → 값을 동기화시켜줘야 함.
function toCelsius(f){
return (f - 32) * 5 / 9;
}
function toFahrenheit(c){
return (c * 9 / 5) + 32;
}
function tryConvert(temperature, convert){
// parameter: (온도 값, 변환하는 함수)
const input = parseFloat(temperature);
if(Number.isNaN(input)){ // exception 처리
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000)/ 1000;
return rounded.toString();
}
tryConvert('abc', toCelsius); // empty string 리턴
tryConvert('10.22', toFahrenheit); // '50.396'을 리턴
✅lifting state up : 하위 컴포넌트의 state를 공통된 상위 컴포넌트의 state로 끌어올리는 것
일반적인 props의 전달 방식은 상위 → 하위의 흐름
lift state up의 경우는 하위 → 상위 → 하위의 흐름
TemperatureInput에서 온도값을 가져오는 부분 수정하기
function TemperatureInput(props){
...
return (
...
// 변경 전: <input value = {temperature} onChange = {setTemperature}/>
<input value = {props.temperature} onChange = {handleChange} />
...
);
}
온도 값을 컴포넌트의 state에서 가져오는 것이 아닌, props를 통해 가져온다.
컴포넌트의 state를 사용하지 않게 되기 때문에, 입력값이 변경되었을 때 상위 컴포넌트로 변경된 값을 전달해주어야 함.
const handleChange = (event) => {
// 변경 전: setTemperature(event.target.value);
props.onTemperatureChange(event.target.value);
}최종적으로 완성된 TemperatureInput 컴포넌트
function TemperatureInput(props) {
// console.log(props);
// 호출 순서 2. : 상위 컴포넌트의 상태 변경 함수(props로 전달된 함수)를 호출
const handleChange = (event) => {
props.onTemperatureChange(event.target.value);
};
return (
<fieldset>
<legend>온도를 입력해주세요. 단위: {scaleType[props.scale]}</legend>
{/* 호출 순서 1 : onChange되면 handleChange 호출*/}
<input type="text" value={props.temperature} onChange={handleChange} />
</fieldset>
);
}
function Calculator() {
const [temperature, setTemperature] = useState('');
const [scale, setScale] = useState('');
const handleCelsiusChange = (temperature) => {
setTemperature(temperature);
setScale('c');
};
const handleFahrenheitChange = (temperature) => {
setTemperature(temperature);
setScale('f');
};
const celsius = scale === 'c' ? temperature : tryConvert(temperature, toCelsius);
const fahrenheit = scale === 'f' ? temperature : tryConvert(temperature, toFahrenheit);
return (
<div>
{/* 호출 순서 3. : 하위 컴포넌트로부터 props.onTemperature의 호출을 받고 특정한 이벤트 핸들러 실행*/}
<TemperatureInput scale="c" temperature={celsius} onTemperatureChange={handleCelsiusChange} />
<TemperatureInput scale="f" temperature={fahrenheit} onTemperatureChange={handleFahrenheitChange} />
<BoilingVerdict celsius={parseFloat(celsius)} />
</div>
);
}

인용 자료 출처
처음 만난 리액트