-
[ReactJS] Lifting State Up프로그래밍/웹 2018. 4. 2. 12:35
Lifting-State-Up.md React Lifting State Up: 홈페이지 원문
Lifting State Up
다수의 컴포넌트가 하나의 데이터 변경에 대해 다같이 변화할 필요가 있는 경우가 있다. 그런 경우 같이 공유하는 데이터을 state를 저장할 컴포넌트를 가장 최상단 컴포넌트로 지정한뒤, 하위 컴포넌트로 전달하는것이 바람직하다.
예제를 위해서 간단하게 물의 끓는점을 판별하는 온도 계산기를 작성하고 테스트 해보도록 하자.
일단은
BoilingVerdict
컴포넌트를 생성하고,celsius
props에 온도를 전달 받은 뒤 끓는 점 판별 여부를 출력하도록 한다. 단순하게 끓는 점 판별만을 하므로 함수형 컴포넌트로 작성한다.이후 유저로부터
<input>
엘리먼트를 통해 온도를 입력 받고state.temperature
에 저장하는Calculator
컴포넌트를 구현한다. 내부에서는BoilingVerdict
컴포넌트를 사용하여 끓는 점 여부를 출력한다.https://codepen.io/gaearon/pen/ZXeOBm?editors=0010
Adding a Second Input
섭씨 온도 말고 화씨 온도도 추가하고 섭씨온도와 화씨 온도 데이터를 항상 똑같게 유지하는 코드를 추가해보자
일단 온도를 측정하는
Calculator
에서 사용자의 입력을 받는 부분만 따로 떼어낸다.코드에서도 볼 수 있고, 코드펜에서 확인도 할 수 있듯이, 2군데에 온도를 입력할 수 있도록 변경했지만, 아직 두개의 온도가 서로 동기화 되고 있지는 않다. 또한 끓는점 여부를 판별하는
BoilingVerdict
컴포넌트도 사용하지 않고 있다. 사용자 입력 폼을TemparatureInput
컴포넌트로 분리하면서 온도 정보가 이동되어Calculator
컴포넌트에서 온도를 확인할 수도 없다.Writing Conversion Functions
일단 섭씨 온도와 화씨 온도의 동기화를 위해 온도 변환 함수를 작성해보자.
위의 함수들을 사용해서 온도변환을 수행하기 위한 헬퍼 함수를 작성해보자. 온도 변환 헬퍼 함수는 기준 온도에 따라서 사용하길 원하는 변환 함수를 매개변수로 입력받는다.
tryConvert
함수를 사용할때는tryConvert('10.22', toFahrenheit)
와 같이 온도와 변환함수를 매개변수로 사용하면 된다.Lifting State Up
현재까지 작성한 코드를 보면,
Calculator
컴포넌트에서 두개의TemperatureInput
을 렌더링 하고, 각각의TemperatureInput
컴포넌트는 고유의temperatur
온도 state를 관리하고 있다. 이 경우 두 컴포넌트 간의 온도 정보가 동기화 되지 않는 문제가 있다. 본래의 목적 자체가 섭씨/화씨 온도를 동기화 시켜서 화면에 표시하는 것이므로 이는 수정되어야 하는 문제이다.리액트에서 컴포넌트 간에 state를 공유할 필요가 있을 경우에는, 해당 state를 상위 컴포넌트로 이동하고 props로 전달하는 방법을 사용한다. 이런 방식을 간편하게 lifting state up 이라고 부른다.
TemperatureInput
컴포넌트에서 사용하는 온도 state를 제거하고Calculator
에서 관리하도록 코드를 수정해보자.일단은
TemperaturInput
컴포넌트에서 사용하던state.temperature
를 전부props.temperature
로 바꾸자.상위 컴포넌트인
Calculator
에서 온도를 관리하고TemperatureInput
컴포넌트로 전달해줄 것이므로, state 온도 정보들을 전부 props로 변경하였다. props는 read-only 이므로 사용자가 온도를 입력해도 props의 temperature에 온도 정보를 저장할 수 없다. 온도 정보는 실제로 컴포넌트의 state로 관리하는Calculator
에 저장해야 한다. 그러나 컴포넌트 내부의 state를 다른 컴포넌트에서 직접 접근 할 수 없으므로,Calculator
컴포넌트가TemperatureInput
을 렌더링 할때 props로 전달해주는 콜백함수를 사용하도록 한다. 콜백함수는onTemperatureChange
에 전달 된다.여기서 props에 전달되는 변수들인 temperature나 onTemperatureChange와 같은 이름은 큰 의미 없이, 코드를 쉽게 구분할 수 있기 위함일 뿐이다.
input
엘리먼트에서 설명했던value
나onChange
와 같은 이름을 사용하여 전달하는 것도 일반적인 방법이다.Calculator
컴포넌트에서 온도 정보를 관리하도록 변경하자. 온도 정보는 섭씨온도 하나로만 관리되는 것이 아니고 화씨온도 정보도 저장하고 있으므로, 이전에 사용하던 state에 온도 단위를 저장하는 state까지 추가하도록 하자.섭씨 온도와 화씨 온도 각각을 따로 state에 저장해도 되지만, 기존에 만들어 놓은 온도 변환 함수들을 사용하면 다른 온도 단위로 변환할 수 있으므로 하나의 온도 state와 단위를 저장하는 state만 존재하면 충분하다.
state에 온도 정보와 단위 정보를 저장하고, 온도와 사용자 입력에 따른 UI 변화를 위한 함수를
TemperatureInput
컴포넌트로 전달하는위처럼
Calculator
컴포넌트까지 수정하고 나면, 유저가 어느 입력 폼에 온도를 입력하든Calculator
컴포넌트의 state로 온도 정보가 업데이트 된다. 한쪽의 input 폼에 입력되면 다른쪽의 input 폼 내용도 자동으로 변환된다.Lessons Learned
상태 정보의 저장이 필요할 경우 컴포넌트의 state에 정보를 추가하고 관리한다. 만일 해당 state를 다른 컴포넌트와 공유할 필요가 있다면, 공통 상위 컴포넌트를 찾아서 그 컴포넌트가 state를 관리하도록 하고 하위 컴포넌트들은 props로 전달받아서 사용하도록 한다. 이러한 작업을
lifting state up
이라고 부른다. 또한 상위 컴포넌트에서 데이터 정보를 하위 컴포넌트로 전달하므로 top-down data flow 라고 할 수도 있다.state를 상위 컴포넌트로 이동하고 사용하는 일은
boilerplate
코드를 더 작성하는 작업을 포함하지만, two-way binding 기법을 사용하는 것보다 버그를 찾는데 훨씬 수월하다. state를 변환하는 컴포넌트가 오직 1개밖에 존재 하지 않으므로, 해당 state와 관련된 버그가 있을 경우 1개의 컴포넌트의setState
관련 구문만 확인하면 되는것이다. 또한 직접적으로 state를 관리하므로 사용자 입력 데이터를 처리하는 추가적인 함수들을 마음껏 작성 할 수 있다.섭씨/화씨 온도를 모두 저장하지 않고 온도 단위와 함께 하나의 온도정보만을 저장했던 것처럼, props나 state의 다른 정보로부터 새로운 정보를 생성할 수 있다면 굳이 state에 저장할 필요가 없다. 하나의 state만 관리하고 변환 함수 (converter function)를 통해 다른 데이터를 생성함으로써, 다른 데이터와 정확하게 동기화를 해줄 수 있는 장점이 있다.
리액트를 이용해 작업을 하다가 UI 상에 문제가 보일 경우, [React Developer Tools]를 사용하면 실시간으로 props와 state 및 UI 변화를 확인할 수 있다. 이를 통해 디버깅을 쉽게 할 수 있다. 아래의 이미지가 디버깅 예제이다.
'프로그래밍 > 웹' 카테고리의 다른 글
[ReactJS] Thinking in React (0) 2018.04.05 [ReactJS] Composition vs Inheritance (0) 2018.04.03 [ReactJS] Forms (0) 2018.03.30 [ReactJS] Lists and Keys (0) 2018.03.29 [ReactJS] Conditional Rendering (0) 2018.03.10