본문 바로가기

React

[React] componentDidUpdate 사용 시점과 무한 루프 렌더링 주의

- 구현 기능 설명 -

  ---------------------------------------------------------------
  버튼  |  번호  | 제목  | 작성자| 조회수| 작성일 | .....
  ---------------------------------------------------------------
    o   |   1   |       |       |       |       |       |       |
  ---------------------------------------------------------------
    o   |   2   |       |       |       |       |       |       |
  ---------------------------------------------------------------
    o   |   3   |       |       |       |       |       |       |
  ---------------------------------------------------------------
    o   |   4   |       |       |       |       |       |       |
  ---------------------------------------------------------------
    o   |   5   |       |       |       |       |       |       |
  ---------------------------------------------------------------


위와 같은 게시판 테이블 있다.
위 테이블에서 버튼을 누르면 모달이 뜬다.
모달은 해달 게시글의 정보를 출력하는 창이다.

버튼을 클릭하면 해당 게시글의 id를 모달에 넘겨준다.
모달은 게시글의 id를 받아와서 axios를 쏜다.
그 결과로 되돌려받은 게시글 상세 정볼르 모달 안에 뿌린다.

 

 

- 모달 출력값이 바뀌지 않음 - 

문제는 몯라이 출력하는 게시글 정보가 초기값으로 고정된 채로 바뀌지 않는다는 점이었다.
버튼을 클릭하면 id를 넘겨주는 것까지 확인했다.
그럼에도 모달 안에 출력되는 상세 정보는 업데이트되지 않았다.
처음에 페이지를 로드할 때 componentDidMount() 를 통해 한 번 실행 뒤에 그 뒤로는 axios 를 다녀오지 않았다.

렌더링을 다시 하도록 유도하려고 클릭한 게시글의 id를 container가 state로 들고 있도록 해 보았다.
그 state를 모달 컨포넌트에 props로 넣어주고 있었다.
그러면 state가 바뀔 때마다 렌더링이 다시 일어날 것이다.
렌더링이 다시 일어나면서 axios도 다시 다녀오고, 화면에 출력되는 정보도 함께 바뀔 것이다.

그러나 위와 같은 내 구상은 생각대로 작돋하지 않았다.
state 가 바뀌고 렌더링이 다시 일어나도 모달은 axios를 다녀오지 않았다.
모달에 넣어주는 props 가 바뀌더라도 모달에 출력되는 상세 정보는 변함이 없었다.
axios는 componentDidMount() 에서 실행하고 있었다.
가장 처음에 화면이 로드될 때 componentDidMount()가 한 번 실행되고 그 뒤로는 실행되지 않는다는 뜻이었다.

 

- 마운트와 렌더링, LifeCycle 함수 -

애초에 componentDidMount() 함수를 다시 실행하도록 만들려던 게 잘못이었다.
모달은 어쨌든 container 안에 박혀 있다.
모달은 container 안에 포함되어 있고, container가 로드될 때 그 안에 있는 모달도 딸려서 함께 로드된다.
이렇게 한 번 마운트된 모들은 state가 바뀌든 props 가 바뀌든 다시 로드되는 일은 없다.
다시 로드되려면 일단 화면으로부터 unmount 되었다가 다시 mount 되어야 한다.
그러나 모달은 unmount 되는 일 없이 컨테이너 안에 붙어 있다.
state 나 props 가 바뀌면 렌더링은 다시 일어날지라도 mount 가 새로 일어나진느 않기 때문이다. 

내가 목표로 삼았어야 하는 LifeCycle 함수는 componentDidMount가 아니라 componentDidUpdate였다.
렌더링이 다시 일어나면 해당 하위 컴포넌트 전체를 새로 불러오는 줄 알았는데 그게 아니었다.
props 가 바뀌는 컴포넌트 단위로 새로 마운트되는 것이 아니라, 값이 변한 DOM 요소 단위로 렌더링이 일어난다.
컨테이너에서 state가 바뀌고 이어서 모달이 받아오는 props가 바뀌는 변화는 componentDidUpdate에서 감지하고 있었다.
componentDidUpdate는 렌더링이 다시 일어났을 때 실행된다.
props가 바뀌거나 setState(), forceUpdate() 등으로 인해서 실행된다.

componentDidUpdate 함수를 쓸 때는 주의할 점이 있다.
조건문으로 변수가 바뀌는지 체크해줘야 한다.
무한 반복, 무한 루프가 발생할 수 있기 때문이다.
렌더링 발생 -> componentDidUpdate() 실행 -> 반영하여 다시 렌더링 -> 다시 componentDidUpdate() 실행...
따라서 조건문으로componentDidUpdate 무한 렌더링을 끊어줘야 한다.
componentDidUpdate 함수는 파라미터로 이전 props를 받아온다.
이를 이용하여 변화를 감지하고 싶은 변수만 따로 조건문에 넣어줘야 한다.

componentDidUpdate(prevProps) {
    if(this.props.userID !== prevProps.userID) {
        this.fetchData(this.props.userID);
    }
}



위와 같은 LifeCycle 함수를 모달에 넣어주면 된다.

 

 

 

- 정리 -

정리하자면 이렇다.
모달은 컨테이너 안에 들어 있다.
페이지가 로드될 때 컨테이너와 함께 모달도 같이 로드된다.
이때 한 번 componentDidMount()가 실행되면 그 뒤로는 다시 실행되지 않는다.
componentDidMount가 실행되려면 unmount 됐다가 다시 mount 되어야 하는데,
모달은 컨테이너에 속해 있어서 처음에 mount 되고 나서 그 뒤로는 unmount 되지 않기 때문이다.
렌더링이 다시 일어나더라도 모달 컴포넌트 전체를 새로 갈아끼우는 방식이 아니라 변화가 필요한 DOM 요소 단위로 렌더링을 다시 한다.

mount 는 다시 일어나지 않지만 렌더링은 다시 일어나기도 한다.
state나 props 등이 바뀌었을 때이다.
모달이 다시 렌더링되는 것을 감지할 수 있는 LifeCycle 함수는 componentDidUpdate이다.
따라서 모달에 componentDidUpdate 함수를 구현해 놓고 props를 바꿔주면 된다.
모달에 넣어주는 props가 바뀌면 렌더링은 다시 일어날 것이고, 
렌더링이 다시 일어나면 componentDidUpdate 함수를 실행할 것이기 때문이다.
단, componentDidUpdate 를 쓸 때는 주의할 점이 있다.
렌더링과 componentDidUpdate 사이에 무한 루프가 발생하지 않도록 렌더링을 끊어주는 조건문을 끼워넣어주어야 한다.


> 참고

https://ko.reactjs.org/docs/react-component.html

 

-  221108
  

반응형