말 그대로 공유된 state를 의미함.

어떤 컴포넌트의 state에 있는 데이터를 여러개의 하위 컴포넌트에서 공통적으로 사용하는 경우를 말함.

어떤 값이 있는 컴포넌트가 있으면 그것에 대하여 그 값에 2를 곱해서 표시하는 컴포넌트와 값이 3을 곱해서 표시하는 컴포넌트 이렇게 두가지 경우가 되는 것처럼..

또 다른 예시를 들어보자면 온도를 받으면 그 온도값에 대해서 온도를 섭씨로 표현하는 컴포넌트와 온도를 화씨로 표현하는 컴포넌트 정도..?

이렇게 지금까지 살펴본것처럼 하위 컴포넌트가 공통된 부모 컴포넌트의 state를 공유하여 사용하는 것을 shared state라고 함.

 

그럼 이제 하위 컴포넌트에서 state 공유하는 것에 대해서 말해보자

아까 예시를 든 온도를 받아서 화씨와 섭씨로 표현해주는 컴포넌트를 만들어보겠음!

우선 섭씨 온도 값을 prop으로 받아서 물이 끓는지 안끓는지를 문자열로 출력해주는 컴포넌트를 만들어보면

function BoilVerdict(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>
       )
  }

이렇게 아까 만든 컴포넌트에 온도를 입력받고 prop으로 온도를 전달해줘서 온도에 따라서 물이 끓는지 안끓는지를 출력하는 것을 짜보았다.

 

그럼 리액트에서의 장점인 재사용성을 올리기위해서 온도를 입력받는 부분도 따로 컴포넌트로 빼와서 만들어줘보겠음.

 

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

이렇게 온도를 입력받는 부분을 추출하였는데 추가적으로 props에 단위를 나타내는 scale을 추가하여 온도의 단위를 섭씨나 화씨로 입력 가능하도록 하였다.

 

그럼 이제 섭씨온도와 화씨온도를 동기화 시키기 위하여 각각 변환하는 두 함수를 만들어주자

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.inNaN(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리턴

다음은 이러한 하위 컴포넌트의 state를 공통된 부모 컴포넌트로 올려서 shared state를 적용해야 함.

여기서 state를 상위 컴포넌트로 올린다는것은? state끌어올리기라고 표현함.

그러면 TemperatureInput 컴포넌트에서 온도 값을 가져오는 부분을 아래와  같이 수정해야함.

return (
	//전 코드: <input value={temperature} onChange={handleChange} />
	<input value={props.temperature} onChange={handleChange} />
    ...
    )

이렇게 하면 온도값을 컴포넌트의 state에서 가져오는 것이 아니라 props를 통해서 가져오게됨 

또 컴포넌트의 state를 사용하지 않게되기때문에 입력값이 변경되었을때 상위 컴포넌트로 그 변경된 값을 전달해주어야하기때문에 handleChange()함수를

const handleChange = (event) => {
	//변경전: setTemperature(event.target.value);
    props.onTemperatureChange(event.target.value);
    }

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

 

최종 완성본

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

마지막으로 변경된 TemperatureInput 컴포넌트에 맞춰서 Calculator 컴포넌트를 변경해주어야함

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>
        	<Temperature
            	scale = "c"
                temperature={celsius}
                onTemperatureChange={handleCelsiusChange} />
           
           <Temperature
            	scale = "f"
                temperature={fahrenheit}
                onTemperatureChange={handleFahrenheitChange} />
           
           <BoilingVerdict
           	celsius={parseFloat(celsius)} />
            
         </div>
      );
   }

 

자 그럼 이걸 실제로 만들어볼거임!

 

이런식으로 온도를 입력받는 컴포넌트를 만들어주고

 

이렇게 온도를 바꿔서 출력해주는 컴포넌트를 만듬!

 

결과물!

끝!!

'REACT' 카테고리의 다른 글

key & form  (0) 2023.07.14
Life cycle and hook  (0) 2023.07.14
React Foundation  (0) 2023.06.27
REACT  (0) 2023.04.29
React  (0) 2022.11.09

+ Recent posts