ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ReactJS] Lifting State Up
    Programming/ReactJS 2022. 12. 1. 11:47

    Shared State

    리액트 개발을 하다보면 하나의 데이터를 여러 개의 컴포넌트에서 표현해야 하는 경우가 생긴다. 이럴 때 가장 가까운 부모 컴포넌트의 데이터를 공유하는 것이 효율적이다. Shared State는 State에 있는 데이터를 여러 개의 하위 컴포넌트에서 공통적으로 사용하는 경우를 의미한다.

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

    function BoilingVerdict(props) {
        if (props.celsius >= 100) {
            return <p>물이 끓습니다.</p>
        }
        return <p>물이 끓지 않습니다.</p>
    } // 자식 컴포넌트
    import { useState } from "react"
    
    function BoilingVerdict(props) {
        if (props.celsius >= 100) {
            return <p>물이 끓습니다.</p>
        }
        return <p>물이 끓지 않습니다.</p>
    }
    
    function Calculator(props) {
        const [temperature, setTemperature] = useState('');
    
        const handleChange = (event) => {
            setTemperature(event.target.value);
        }
    
        return (
            <fieldset>
                <legend>섭씨 온도를 입력하세요 : </legend>
                <input
                    value = {temperature}
                    onChange = {handleChange} />
                <BoilingVerdict
                    celsius = {parseFloat(temperature)} />
            </fieldset>
        )
    } // 부모 컴포넌트

    입력 컴포넌트 추출

    import { useState } from "react"
    
    function BoilingVerdict(props) {
        if (props.celsius >= 100) {
            return <p>물이 끓습니다.</p>
        }
        return <p>물이 끓지 않습니다.</p>
    }
    
    function Calculator(props) {
        const [temperature, setTemperature] = useState('');
    
        const handleChange = (event) => {
            setTemperature(event.target.value);
        }
    
        return (
            <fieldset>
                <legend>섭씨 온도를 입력하세요 : </legend>
                <input
                    value = {temperature}
                    onChange = {handleChange} />
                <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 = {handleChange} />
            </fieldset>
        )
    }
    function Calculator(props) {
        return (
            <div>
                <temperatureInput scale = "c" />
                <temperatureInput scale = "f" />
            </div>
        )
    }

    온도 변환 함수 작성하기

    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();
    }

    실제 사용

    tryConvert('abc', toCelsius); // empty string을 리턴
    tryConvert('10.22', toFahrenheit); // 50.396을 리턴

    Shared State 적용하기

    하위 컴포넌트의 state를 공통 상위 컴포넌트로 올리는 것이다. 이를 위해서는 다음과 같이 소스를 변경해줘야 한다.

    // 변경 전 <input value = {temperature} onChange = {handleChange} />
    <input value = {props.temperature} onChange = {handleChange} />
    // 변경 전 : onTemperatureChange(event.target.value);
    props.onTemperatureChange(event.target.value);

    최종적인 모습은 다음과 같다.

    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>
        )
    }
    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>
        )
    }

    < Source />

    TemperatureInput.jsx

    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 = {onTemperatureChange} />
            </fieldset>
        )
    }
    
    export default TemperatureInput;

    Calculator.jsx

    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(celcius) {
        return (celcius * 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;

    ※ 본 게시글은 소플님의 강의 영상을 참고하여 작성되었습니다. 개인적인 공부 목적으로 사용하고 있고, 문제 시 비공개 전환하도록 하겠습니다.

    'Programming > ReactJS' 카테고리의 다른 글

    [ReactJS] Composition vs Inheritance  (0) 2022.12.01
    [ReactJS] Forms  (0) 2022.12.01
    [ReactJS] List and Keys  (0) 2022.11.30
    [ReactJS] Conditional Rendering  (0) 2022.11.30
    [ReactJS] Handling Events  (0) 2022.11.30

    댓글