- 하나의 데이터를 여러 컴포넌트에서 다뤄야 할때가 많다
- 부모 state를 만들어 각각의 컴포넌트에서 공유하여 사용한다
섭씨온도에서 물이 끓는지 안끊는지 코드
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); // onChange로 인해 변경되는 input태그의 값을 setTemperature에 대입 } return ( <fieldset> <legend>섭씨 온도를 입력하세요:</legend> <input value={temperature} // 처음에는 useState('')로 인해 공백으로 초기화 되어있다 onChange={handleChange}/> <BoilingVerdict celsius={parseFloat(temperature)}/> // temperature는 스트링타입임으로 parseFloat으로 실수형타입으로 변경해 BoilingVerdict컴포넌트에게 주었다 </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> ) }추출당한 Calculator컴포넌트
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)) { // isNaN : is Not a number, 숫자가 아닌 타입의 값을 입력했을 경우 return ''; } const output = convert(input); // input 안에 temperature값이 들어가 있다 const rounded = Math.round(output * 1000) / 1000; return rounded.toString(); }tryConvert컴포넌트 사용하기
tryConvert('abc', toCelsius); // empty string을 리턴 tryConvert('10.22', toFahrenheit); //'50.396'을 리턴Shared State적용하기
- Lifting state up : 하위 컴포넌트의 state를 상위 state(부모)로 올린다는 뜻
- 입력 컴포넌트 추출하기 -> 에서 return 부분을 수정하면 된다return ( ... //<input value={temperature} onChange={handleChange}/> <input value={props.temperature} onChange={handleChange}/> ... )- 입력 컴포넌트 추출하기 -> 에서 handleChange 부분을 수정하면 된다
const handleChange = (event) => { //setTemperature(event.target.value); props.onTemperatureChange(event.target.value); }- 입력 컴포넌트 추출하기 -> 최종결과
const scaleNames = { c: '섭씨', f: '화씨' }; function TemperatureInput(props) { // const [temperature, setTemperature] = useState(''); state대신 props에서 값을 전달 받는다 const handleChange = (event) => { //setTemperature(event.target.value); props.onTemperatureChange(event.target.value); } return ( <fieldset> <legend> 온도를 입력해 주세요(단위:{scaleNames[props.scale]}: </legend> <input value={props.temperature} onChange={handleChange} /> </fieldset> ) }Calculator 컴포넌트 변경하기
function Calculator(props) { const [temperature, setTemperature] = useState(''); const [scale, setS cale] = useState('c'); // 섭씨로 초기화 const handleCelsiusChange = (temperature) => { setTemperature(temperature); // 전달받은 값으로 temperature설정 setScale('c');// 온도 단위를 섭씨로 변경 } const handleFahrenheitChange = (temperature) => { setTemperature(temperature);// 전달받은 값으로 temperature설정 setScale('f');// 온도 단위를 섭씨로 변경 } const celsius = scale === 'f' ? tryConvert(temperature, toCelsius):temperature; // 섭씨로 들어온 값의 scale이 맞다면 tryConvert를 통해 toCelsius로 섭씨로 변경, 아니면 temperature로 그냥 전달 const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit):temperature; // 화씨로 들어온 값의 scale이 맞다면 tryConvert를 통해 toFahrenheit으로 화씨로 변경, 아니면 temperature로 그냥 전달 return ( <div> <TemperatureInput scale="c" // 섭씨로 변경 temperature={celsius} // celsius를 통해 들어온 값이 섭씨가 맞으면 섭씨단위로 값을 변경 // TemperatureInput컴포넌트의 input 타입의 벨류를 celsius로 변경 onTemperatureChange={handleCelsiusChange}/> // handleCelsiusChange 핸들러를 통해 setTemperature(), setScale() <TemperatureInput scale="f" // 화씨로 변경 temperature={fahrenheit} // fahrenheit을 통해 들어온 값이 화씨가 맞으면 화씨단위로 값을 변경 // TemperatureInput의 input 타입의 벨류를 fahrenheit 변경 onTemperatureChange={handleFahrenheitChange}/> // handleFahrenheitChange 핸들러를 통해 setTemperature(), setScale() <BoilingVerdict celsius={parseFloat(celsius)}/> </div> ); }