Scenario


ReactNative로 타이머를 만들고 있는데,

Props에 따라 state를 변화시켜야 할때, componentWillReceiveProps(newtProps)를 써야할때가 있다.

*(이 메소드 안에서 this.setState()를 해도 추가적으로 렌더링하지 않는다.)


JavaScript 0.44 KB
  1.     componentWillReceiveProps (nextProps) {
  2.         const currentProps = this.props;
  3.         if(!currentProps.isPlaying && nextProps.isPlaying) {
  4.             const timerInterval = setInterval(() => {currentProps.addSecond();}, 1000);
  5.             this.setState({
  6.                 timerInterval
  7.             })
  8.         } else if(currentProps.isPlaying && !nextProps.isPlaying) {
  9.             clearInterval(this.state.timerInterval);
  10.         }
  11.     }


위 코드가 타이머에서 elapsedTime(지금까지 카운팅한 시간) state를 증가시키는 로직인데,


if(!currentProps.isPlaying && nextProps.isPlaying)

이런식으로 조건을 주는게 직관적이지도 않고 왠지 비효율적으로 보였다.


이 소스를 단지 

if(nextProps.isPlaying

이런식의 조건식으로 바꿀수 없는것일까? 생각해보았다.


Solution


결론부터 말하자면 componentWillReceiveProps(newtProps) 에서 setState를 해야할 경우에는 무조건 이전값과 다음값을 비교한뒤에 해야한다.


현재 props와 next props를 비교하지 않고 setState를 하면 어떻게 되는지 알아보기위해


  1.         if(currentProps.isPlaying) {
  2.             const timerInterval = setInterval(() => {currentProps.addSecond();}, 1000);
  3.             this.setState({
  4.                 timerInterval
  5.             })
  6.         }

이런식으로 소스코드를 바꿨더니, setInterval 함수가 여러번 실행되서 카운팅 속도가 1초주기가 아닌, 점점 빨라졌다.



(카운트가 빨라진 앱의 모습)



왜 그럴까?



그림 출처: https://velopert.com/1130 - velopert님


일단 Reactjs Life Cycle 부터 살펴보자면 위와 같다.


만약 Prop의 변화를 감지해서 State를 변환시켜 줄때는 componentWillReceiveProps에서 해주는게 맞다.


왜냐하면 shouldComponentUpdate 이후에는 setState를 할 수 없다.


--------------------------------------------------------

본론으로 들어가서 왜 그럴까?


Note that React may call this method even if the props have not changed, so make sure to compare the current and next values if you only want to handle changes. This may occur when the parent component causes your component to re-render.

출처:https://reactjs.org/docs/react-component.html


리액트 공식문서를 살펴보면 componentWillReceiveProps에 대해 위와같이 서술하고 있다.

"이 메소드는 props가 변하지 않더라도 Call 할 수 있으므로, 현재 current value와 next value를 꼭 비교해서 써야하며, 이는 상위 component가 너의 컴포넌트를 re-render 시킨다" 고 설명한다


더 이해하기 쉽게 예를들어보자,


예를들어, 타이머가 현재 카운팅을 하고있어서 현재 isPlaying 값이 true라고 가정해보자.

현재 isPlaying이 true 면서 props가 바뀌지 않았을때 componentWillReceiveProps 메소드를 콜 한다면, if(nextProps.isPlaying) 의 조건식은 항상 참 일수 밖에없다.


그러나 if(!currentProps.isPlaying && nextProps.isPlaying) 형식으로 조건문을 걸어준다면, false && true 이므로, props가 변동이 있을때만, 이 조건문이 실행되게 되는 것 이다.


 

 current.isPlaying

nextProps.isPlaying

when props are not Changed

 true

 true

when props are Changed

 true

 false 



+ Recent posts