[React] Shared State

문지은·2023년 7월 23일
0

React

목록 보기
11/24
post-thumbnail

Shared State

  • 어떤 컴포넌트의 state에 있는 데이터를 여러 개의 하위 컴포넌트에서 공통적으로 사용하는 경우
  • 아래와 같이 자식 컴포넌트에서 각각 값을 가지고 있을 필요 없이 부모 컴포넌트에서 가지고 있는 값을 사용하는 경우를 예를 들 수 있음

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

사용자로부터 온도를 입력받아서 각각 섭씨온도와 화씨온도로 표현해주고 해당 온도에서 물이 끓는지 안 끓는지를 출력해주는 컴포넌트를 만들면서 state를 공유하는 방법에 대해 알아보자.

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

  • 섭씨 온도 값을 props로 전달 받아 물이 끓는지 안끓는지 문자열로 출력해주는 컴포넌트
function BoilingVerdict(props) {
    if (props.celsius >= 100) {
        return <p>물이 끓습니다.</p>;
    }
    return <p>물이 끓지 않습니다.</p>;
}
  • 위에서 작성한 BoilingVerdict 컴포넌트를 사용할 부모 컴포넌트
    • 사용자가 온도 값을 변경할 때마다 handleChange() 함수가 호출되고 setTemperature() 함수를 통해 온도 값을 갖고 있는 temperature라는 state 변경
function Caculator(props) {
    const [temperature, setTemperature] = useState('');

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

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

입력 컴포넌트 추출하기

  • Calculator 컴포넌트 안에 온도를 입력하는 부분을 별도의 컴포넌트로 추출
    • 섭씨온도와 화씨온도를 각각 따로 입력받을 수 있도록 하여 재사용이 가능한 형태로 컴포넌트를 만들어 사용하기 위해
const scaleNames = {
    c: '섭씨',
    f: '화씨'
}

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

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

    return (
        <fieldset>
            <legend>온도를 입력해 주세요(단위:{scaleName[props.scale]});</legend>
            <input 
                value={temperature}
                onChange={handleChage} />
        </fieldset>
    )
}
  • 이제 위에서 작성한 코드를 사용하여 Calculator 컴포넌트를 변경하면 아래와 같다.
function Caculator(props) {
    return (
        <div>
            <TemperatureInput scale="c" />
            <TemperatureInput scale="f" />
        </div>
    )
}
  • 사용자가 입력하는 온도 값이 Temperature의 state에 저장되기 때문에 섭씨온도와 화씨온도 값을 따로 입력받으면 두 개의 값이 다를 수 있다.
    • 따라서 두 값을 동기화 시켜주어야 한다.

온도 변환 함수 작성하기

  • 섭씨온도와 화씨온도 값을 동기화 시키기 위해서 각각 변환하는 함수를 작성해보자.
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();
}

Shared State 적용하기

  • 이제 하위 컴포넌트의 State를 공통된 부모 컴포넌트로 올려서 shared state를 적용해보자.
  • 온도 값을 컴포넌트의 state에서 가져오는 것이 아닌 props를 통해서 가져오기
  • 컴포넌트의 state를 사용하지 않기 때문에 입력값이 변경되었을 때 상위 컴포넌트로 변경된 값을 전달해주기 위해 handleChange() 함수 수정
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;

Calculator 컴포넌트 변경하기

  • 변경한 TemperatureInput 컴포넌트에 맞춰서 Calculator 컴포넌트 변경
  • state로 temperature와 scale을 선언하여 온도 값과 단위를 각각 저장
    • 이 온도와 단위를 이용하여 변환 함수를 통해 섭씨온도와 화씨온도를 구함
  • TemperatureInput 컴포넌트를 사용하는 부분에서는 각 단위로 변환된 온도 값과 단위를 props로 넣어주고, 값이 변경되었을 때 업데이트하기 위한 함수를 onTemperatureChange에 넣어줌
    • 섭씨온도가 변경되면 단위가 c로 변경되고, 화씨온도가 변경되면 단위가 f로 변경됨
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>
    );
}

최종 컴포넌트 구조

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

실행 결과

  • 입력한 값에 따라 자동으로 값이 변환되어 나오는 것을 확인할 수 있음

실습 전체 코드

References

profile
코드로 꿈을 펼치는 개발자의 이야기, 노력과 열정이 가득한 곳 🌈

2개의 댓글

comment-user-thumbnail
2023년 7월 23일

좋은 정보 얻어갑니다, 감사합니다.

1개의 답글