본문 바로가기

react

[소플] ch 12. State 끌어올리기

1. shared State

 

- 공유된 state

- 자식 컴포넌트들이 가장 가까운 부모 컴포넌트의 state를 공유해서 사용

- 어떤 컴포넌트의 state에 있는 여러 개의 하위 컴포넌트에서 공통적으로 사용하는 경우 

 

 

- 부모 컴포넌트는 degree라는 이름의 섭씨온도 값을 갖고 있음

- 컴포넌트 C는 온도를 섭씨로 표현하는 컴포넌트 

- 컴포넌트 F는 온도를 화씨로 표현하는 컴포넌트 

 

- 자식 컴포넌트들이 각각 온도 값을 가지고 있을 필요 없이, 부모 컴포넌트의 state에 있는 섭씨온도 값을 변환해서 표시해주면 됨 

 

 

2. 하위 컴포넌트에서 State 공유하기 

 

- 사용자로부터 온도를 입력받아서 각각 섭씨온도와 화씨온도로 표현해 주고 해당 온도에서 물이 끓는지 안 끓는지를 출력해주는 컴포넌트 

 

1) 물의 끓음 여부를 알려주는 컴포넌트 

 

BoilingVerdict 컴포넌트 

 

- 섭씨 온도 값을 props로 받아서 100도 이상이면 물이 끓는다는 문자열을 출력하고, 그외에는 물이 끓지 않는다는 문자열 출력

function BoilingVerdict(props) {
    if(props.celsius >=100) {
        return <p>물이 끓습니다.</p>;
    }
    return <p>물이 끓지 않습니다.</p>;
}

 

Calulator 컴포넌트 

 

- state로 온도 값을 하나 갖고 있음

- 사용자로부터 입력을 받기 위해서 <input> 태그를 사용하여 제어 컴포넌트로 구현 

- 사용자가 온도 값을 변경할 때마다 handleChange() 함수가 호출되고, setTemperature() 함수를 통해 온도 값을 갖고 있는 temperature라는 이름의 state를 업데이트 

- state에 있는 온도값은 BoilingVerdict 컴포넌트의 celsius props로 전달 

 

function Calculator(props) {
    const [temperature, setTemperature] = useState('');

    const handleChange = (event) => {
        setTemperature(event.target.value);
    }

    return (
        <fieldset>
            <legend>섭씨 온도를 입력하세요:</legend>
            <input  
                value={temperature}
                onChange={handleChange} />
        </fieldset>
    )
}

 

 

2) 입력 컴포넌트 추출하기 

 

- Calculator 컴포넌트 안에 온도를 입력하는 부분은 별도의 컴포넌트로 추출   

  -> 섭씨 온도와 화씨 온도를 각각 따로 입력받을 수 있도록 하여 재사용이 가능한 형태로 컴포넌트 작성

 

TemperatureInput 컴포넌트 

 

- props에 단위를 나타내는 scale을 추가하여 온도의 단위를 섭씨 또는 화씨로 입력가능하도록 만듬 

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={handleChange} />
        </fieldset>
    )
}

 

Calculator 컴포넌트 변경

 

- 총 두개의 입력을 받을 수 있도록 되어있으며 하나는 섭씨온도를 입력받고 다른 하나는 화씨 온도를 입력받음 

- 사용자가 입력하는 온도 값이 TemperatureInput의 state에 저장되기 때문에 섭씨온도와 화씨온도 값을 따로 입력받으면 두 개의 값이 다를 수 있는 문제 발생 

  -> 값을 동기화시켜줘야 함 

 

function Calculator(props) {
     return (
    	<div>
        	<TemperatureInput scale="c" />
            <TemperatureInput scale="f" />
        </div>
     );
}

 

3) 온도 변환 함수 작성하기 

 

- 섭씨온도와 화씨온도 값을 동기화시키기 위해서 각각 변환하는 함수를 작성해야 함 

//화씨온도를 섭씨온도로 변환 
function toCelsius(fahrenheit) {
	return (fahrenheit - 32) * 5 / 9;
}

//섭씨온도를 화씨온도로 변환 
function toFahrenheit(celsius) {
	return (celsius * 9 / 5) + 32;
}

 

tryConvert 함수 

 

- 온도 값과 변환하는 함수를 파라미터로 받아서 값을 변환시켜 리턴해주는 함수 

- 숫자가 아닌 값을 입력하면 empty string을 리턴하도록 예외 처리 

function tryConvert(temperature, convert) {
    const input = parseFloat(temperature);
    if(Number.isNaN(input)) {
    	return '';
    }
    const output = convert(input);
    const rounded = Math.round(output * 1000) / 1000;
    return rounded.toString();
}

 

4) Shard State 적용하기 

 

State 끌어올리기 (Lifting State Up)

 

- 하위 컴포넌트의 state를 공통된 부모 컴포넌트로 올려서 shared state 적용 

 

 

TemperatureInput 컴포넌트 수정 

 

- 온도 값을 state에서 가져오는 것이 아닌 props를 통해서 가져오기 

return (
    ...
    <input value={props.temperture} onChange={handleChange} />
    ...
)

 

- 컴포넌트의 state를 사용하지 않게 되기 때문에 입력값이 변경되었을 때 상위 컴포넌트로 값을 전달해줘야 함 

- 사용자가 온도 값을 변경할 때마다 props에 있는 onTemperatureChange() 함수를 통해 변경된 온도 값이 상위 컴포넌트로 전달 

const handleChange = (event) => {
   props.onTemperatureChange(event.target.value);
}

 

완성된 TemperatureInput  컴포넌트 

 

- props로 scale과 temperature를 받아서 표시해주며, 온도 값이 변경되었을 때는 props로 onTemperatureChange() 함수를 호출하여 상위 컴포넌트로 변경된 값을 전달 

const scaleNames = {
    c:'섭씨', 
    f:'화씨'
};

function TemperatureInput(props) {
    const handleChange = (event) => {
        props.onTemperatureChange(event.target.value);
    };
    
    return (
        <fieldset>
            <legend>온도를 입력해주세요(단위:{scaleNames[props.scale]}):</legend>
            <input value={props.temperature} onChange={handleChange} />
        </fieldset>
    )
}

export default TemperatureInput;

 

 

5) Calculator 컴포넌트 변경하기 

 

완성된 Calculator 컴포넌트 

 

- state로 temperature와 scale을 선언하여 온도 값과 단위를 각각 저장하도록 함 

- 이 온도와 단위를 이용하여 변환 함수를 통해 섭씨온도와 화씨온도를 구해서 사용

 

- TemperatureInput 컴포넌트를 사용하는 부분에서는 각 단위로 변환된 온도 값과 단위를 props로 넣어 주었고, 값이 변경되었을때 업데이트하기 위한 함수를 onTemperatureChange에 넣어줌

 

- 섭씨온도가 변경되면 단위가 'c'로 변경되고, 화씨온도가 변경되면 단위가 'f'로 변경됨 

 

import React, { useState } from "react";
import TemperatureInput from "./TemperatureInput";

function BoilingVerdict(props) {
    if(props.celsius >= 100) {
        return <p>물이 끓습니다.</p>;
    }
    return <p>물이 끓지 않습니다.</p>;
}

//화씨온도를 섭씨온도로 변환 
function toCelsius(fahrenheit) {
	return (fahrenheit - 32) * 5 / 9;
}

//섭씨온도를 화씨온도로 변환 
function toFahrenheit(celsius) {
	return (celsius * 9 / 5) + 32;
}

function tryConvert(temperature, convert) {
    const input = parseFloat(temperature);
    if(Number.isNaN(input)) {
    	return '';
    }
    const output = convert(input);
    const rounded = Math.round(output * 1000) / 1000;
    return rounded.toString();
}

function Calculator(props) {
    const [temperature ,setTemperature] = useState("");
    const [scale, setScale] = useState("c");

    const handleCelsiusChange = (temperature) => {
        setTemperature(temperature);
        setScale("c");
    };

    const handleFahrenheitChange = (temperature) => {
        setTemperature(temperature);
        setScale("f");
    };

    const celsius =
        scale === "f"? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = 
        scale === "c"? tryConvert(temperature, toFahrenheit) : temperature;

    return (
        <div>
            <TemperatureInput
                scale="c"
                temperature={celsius}
                onTemperatureChange={handleCelsiusChange}
            />
            <TemperatureInput   
                scale="f"
                temperature={fahrenheit}
                onTemperatureChange={handleFahrenheitChange}
            />
            <BoilingVerdict celsius={parseFloat(celsius)} />
        </div>
    )
}

export default Calculator;

 

 

- 상위 컴포넌트인 Calculator에서 온도 값과 단위를 각각의 state로 가지고 있으며, 두 개의 하위 컴포넌트는 각각 섭씨와 화씨로 변환된 온도 값과 단위 그리고 온도를 업데이트하기 위한 함수를 props로 가지고 있음

 

 

3. 실습 - 섭씨온도와 화씨온도 표시하기 

 

'react' 카테고리의 다른 글

[소플] ch 14. 컨텍스트  (1) 2023.10.30
[소플] ch 13. 합성 vs 상속  (0) 2023.10.30
[소플] ch 11. 폼  (0) 2023.10.29
[소플] ch 10. 리스트와 키  (0) 2023.10.28
[소플] ch 9. 조건부 렌더링  (1) 2023.10.28