-
[ReactJS] Lifting State UpProgramming/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