본문 바로가기

Joyful 디버깅

[React] React 리액트 Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state. 에러 해결

728x90
반응형

const logOutButtonClickHandler = () => {
    localStorage.removeItem('jwt');
    localStorage.removeItem('registerState');
    location.reload();
  };

react_devtools_backend.js:2273 Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.

→ 로그아웃 이후 로그인 화면으로 돌아왔을 때 위와 같은 오류가 발생했다.

 

처음엔 화면이 전부 렌더되지 않았을 때 사용자가 시작하기 버튼 클릭 시 위와같은 에러가 나타났었기 때문에 그 부분을 해결하려고 했다.

 

 

해결방안-1 (실패)

그래서 logIn 컴포넌트에서 useState에 버튼 활성화 상태값을 만들어서 useEffect를 이용해 컴포넌트가 전부 렌더링 된 후에 버튼활성화값을 true로 바꿔주고, 버튼클릭핸들러에 버튼활성화 값이 false인 경우 return 하도록 로직을 변경했다.

하지만 에러는 그대로 나타났다.

 

→ 문제의 원인을 잘못 파악한 경우

 

해결방안-2 (성공)

아무래도 화면이 전부 렌더되지 않았을 때 클릭해서 생긴 문제가 아닌 것 같다.

Render methods should be a pure function of props and state

 

이 부분을 생각해봤다.

참고 : https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/birth/component_render.html

 

Component render() · react-indepth

 

developmentarc.gitbooks.io

In both cases, we have the core principle of keeping render() a pure method. What does that mean? That means we shouldn't call setState(), query the Native UI or anything else that can mutate the existing state of the application. The reason why is if we do this kind of interaction in render(), then it will kickoff another render pass. Which once again, triggers render() which then does the same thing... infinitely.

 

그러니까 렌더함수가 pure해야 한다는 것은, 렌더 함수 속에 setState와 같이 상태값을 변경하는 로직이 들어가면 안 된다는 것이었다.

 

 

render() {
  // BAD: Do not do this!
  this.setState({ foo: 'bar' });
  return (
    <div className={ classNames('person', this.state.mode) }>
      { this.props.name } (age: { this.props.age })
    </div>
  );
}

 

만약 위와 같은 render() 함수 속에 setState(위에선 class문법이라. this.state)를 사용한다면 렌더하는 중에 상태값을 변경하게 되고 그럼 다시 렌더링, 그 렌더링 과정에서 또 상태값을 변경하게 되고 또 다시 렌더링... 의 무한 루프에 빠지게 된다는 것이다.

 

그런데, 내 코드에서는 렌더함수에 상태값을 변경하는 로직이 없는데 왜 저런 에러 메시지가 떴을까?

 

어딘가 숨어서 렌더링 함수를 방해하는 것이 있는지 찾아보았다.

 

우선 처음 로그인 화면이 렌더링 될 때에는 문제가 없는데, 다른 페이지에서 로그아웃 버튼을 눌러 로그인 화면으로 돌아올 때만 문제가 생겼다.

 

const logOutButtonClickHandler = () => {
    localStorage.removeItem('jwt');
    localStorage.removeItem('registerState');
    history.push('/logIn');
  };

 

history.push 부분이 아주 의심스러웠다.

 

다른 코드들을 이리저리 살펴보다보니,

 

이미 localStorage에 토큰 값이 없으면 logIn으로 돌리는 로직을 app.js 에 제한된 라우트 컴포넌트에 만들어뒀는데 또다시 로그인 화면으로 이동시키는 로직이 생겨서 문제인 것 같다.

 

const logOutButtonClickHandler = () => {
    localStorage.removeItem('jwt');
    localStorage.removeItem('registerState');
    location.reload();
  };

 

이렇게 새로고침만 해주는 로직으로 변경했더니 문제가 해결되었다.

 

 

 

2020년 11월 16일 벨로그에 올렸던 글 

728x90
반응형