React의 componentDidUpdate 사용할 때 주의점: 무한루프

2019. 7. 24. 12:49프론트엔드 개발/React

componentDidUpdate()에서 setState()를 즉시 호출할 수도 있지만, ... 조건문으로 감싸지 않으면 무한 반복이 발생할 수 있다는 점에 주의하세요. - React 공식문서

 

componentDidUpdate(){
  ...
  this.setState({currentAddress:items[0].region.area3.name});
}

 

React로 프로젝트를 진행하다 특이한 현상을 발견했습니다. 화면을 render한 직후 다음 단계에서 외부 API 호출을 하기 위해 componentDidUpdate()를 사용하는데 여기서 위의 코드처럼 setState()를 사용하니 무한루프에 빠지는 것입니다.

 

아... 내 무료 호출 한도....ㅠ

 

특히나 외부 API를 호출하는 로직이 들어가있어 이 상태로 5분만 내버려두면 한달치 무료 호출량을 전부 다 쓸 것 같아 얼른 조치를 취해야겠다고 생각했습니다. 검색하니 이런 현상을 겪는 것이 저만은 아니라는 것을 알게 되었습니다.

 

 

setState() inside of componentDidUpdate()

I'm writing a script which moves dropdown below or above input depending on height of dropdown and position of the input on the screen. Also I want to set modifier to dropdown according to its dire...

stackoverflow.com

You can use setState inside componentDidUpdate. The problem is that somehow you are creating an infinite loop because there's no break condition.

Based on the fact that you need values that are provided by the browser once the component is rendered, I think your approach about using componentDidUpdateis correct, it just needs better handling of the condition that triggers the setState.

- damianmr, stackoverflow

채택된 답변의 내용으로 요지는 componentDidUpdate()에서 state를 수정하는 setState()를 쓰려면 break를 위한 조건을 써야 한다는 겁니다. 아래와 같이 코드를 수정함으로써 문제를 해결했습니다.

 

componentDidUpdate(){
  ...
  if(this.state.currentAddress !== items[0].region.area3.name){
    this.setState({currentAddress:items[0].region.area3.name});
  }
}

 

 

 

React.Component – React

A JavaScript library for building user interfaces

ko.reactjs.org

조금 더 구체적으로 들어가면, 리엑트 공식 문서에서는 다음과 같은 설명과 예시 코드를 보여주고 있습니다.

componentDidUpdate(prevProps) {
  // 전형적인 사용 사례 (props 비교를 잊지 마세요)
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

componentDidMount()는 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출됩니다. DOM 노드가 있어야 하는 초기화 작업은 이 메서드에서 이루어지면 됩니다. 외부에서 데이터를 불러와야 한다면, 네트워크 요청을 보내기 적절한 위치입니다.
...
componentDidUpdate()에서 setState()를 즉시 호출할 수도 있지만, 위의 예시처럼 조건문으로 감싸지 않으면 무한 반복이 발생할 수 있다는 점에 주의하세요.
- React 공식문서의 ComponentDidUpdate()

 

공식문서의 예시 코드를 보면 props를 fetchData라는 함수(함수명에 비추어 보아 네트워크 요청을 보내는 함수로 보입니다.)의 인자로 넣고 실행할 때, 인자로 받은 prevProps의 userID와 (상위 컴포넌트에서 받은 것으로 보이는) 현재 porps를 비교하는 조건문을 넣어줬습니다. 그리고 setState()을 사용할 때에도 같은 방식으로 하지 않으면 무한 반복이 일어날 수 있다고 합니다.

 

React는 상태를 변경할 때마다 화면을 리렌더하니, 렌더 후 실행하는 componentDidUpdate()에서 상태를 변경하면 렌더 -> componentDidUpdate() -> 상태변경 -> 렌더 -> componentDidUpdate() -> 상태변경 -> ... 식으로 무한루프에 빠지는 것 같습니다.

 

그런데 componentDidUpdate()에서 props를 외부 api에 호출했을 때, 즉 리엑트 공식문서에서 나온 예시 코드는 성능저하만 일어난다는건지 무한루프가 일어난다는건지 정확한 설명이 없어서 여기에 대해서는 조금 더 알아봐야 할 것 같습니다.

 

 

componentDidUpdate()와 setState()의 상관관계는 생각보다 잊고 지나치기 쉬워 프로젝트를 진행하면서 종종 마주치게 됩니다. 불필요한 코드 실행과 성능저하 등을 야기하니 꼭 한번 짚고 넘어가시길 추천합니다.