Dev/트러블슈팅, 오류해결록

React ) 컴포넌트 안 바뀜, 안 사라짐, 쌓임 현상 디버깅

potato-hyun 2021. 9. 30. 00:32

리액트로 프론트엔드 작업을 하며, 기능 단위로 컴포넌트를 나눠 사용하고 있었다. 회원 유형에 따라 컴포넌트를 보이거나 숨기는 방식이었다. 

{/* render() 부분 */}
<div className={"col-sm "}>
  {/* ========== A유형 a컴포넌트 ========== */}
  { Number(user.userRole) === CONFIG.USER_ROLE.artist && <UserArtworkTable key={user.userIndex} ... />}

  {/* ========== A유형  aa컴포넌트 ========== */}
  { Number(user.userRole) === CONFIG.USER_ROLE.artist && <UserPivotsTable key={user.userIndex} ... />}

  {/* ========= B유형 b컴포넌트========== */}
  { Number(user.userRole) === CONFIG.USER_ROLE.vip && <UserCollectionTable key={user.userIndex} ... />}
</div>

그런데 여기서 오류가 발생했다. 분명 회원 유형이 (A)일때 컴포넌트 (a)가 잘 나왔는데, 회원 유형을 (B)로 바꾸고 다시 (A)로 갔을때 컴포넌트 (a)가 두개가 되었다. 심지어 이전에 나왔던 (a) 컴포넌트는 지워지지도 않았다.

state 오브젝트를 잘 못 읽어 오는걸까? 아님, 조건부 랜더링을 너무 남발한걸까? 디버깅 코드로 조건부 결과를 boolean으로 찍어보았지만, 의도한 값대로 나왔다. 그렇게 계속 삽질하던중, 발견한 단비같은 블로그... 원리부터, 해결법까지 완벽!

 

컴포넌트의 prop이나 state가 변경되면 React는 새로 반환된 엘리먼트를 이전에 렌더링된 엘리먼트와 비교해서 실제 DOM 업데이트가 필요한지 여부를 결정합니다. 같지 않을 경우 React는 DOM을 업데이트합니다.

→  리액트 글 참고

 

리액트는 이전 DOM과 달라진 부분을 비교해 찾아내고, 업데이트가 필요하면 리랜더링하는 방식이다. 대표적으로 props, state가 있다. 여기에 중요한 비교 조건이 하나 더 있는데, 바로 key 이다.

리액트로 컴포넌트화 하고 개발하면서 제일 많이 보는 오류가 "key 좀 명시해라"인 것 같다. 항시 바빠서 key는 건너뛰고, props에 의존해왔는데... 아무튼 리액트는 컴포넌트의 고유값 key를 기준으로 DOM을 비교하기도 한다는 것.

 

이전에 내가 작성한 코드를 보자.

{/* render() 부분 */}
<div className={"col-sm "}>
  {/* ========== A유형 a컴포넌트 ========== */}
  { Number(user.userRole) === CONFIG.USER_ROLE.artist && <UserArtworkTable key={user.userIndex} userIndex={user.userIndex} updateUserFunc={this.updateUser}/>}

  {/* ========== A유형  aa컴포넌트 ========== */}
  { Number(user.userRole) === CONFIG.USER_ROLE.artist && <UserPivotsTable key={user.userIndex} user={user} updateUserFunc={this.updateUser}/>}

  {/* ========= B유형 b컴포넌트========== */}
  { Number(user.userRole) === CONFIG.USER_ROLE.vip && <UserCollectionTable key={user.userIndex} userIndex={user.userIndex} updateUserFunc={this.updateUser} />}
</div>

언뜻보면 문제없는 코드 같아 보이지만, 다음 세 가지 컴포넌트를 주목해보자.

  • <UserCollectionTable key={user.userIndex} ... />
  • <UserArtworkTable key={user.userIndex} ... />
  • <UserPivotsTable key={user.userIndex} ... />

세 컴포넌트의 잘못된 점, 바로 Key 값이 동일하다는 것이다. 세 컴포넌트 모두, 부모 컴포넌트가 같기 때문에 userIndex가 같은데, (A) 유형일때 만들어진 (a) 컴포넌트와 (aa) 컴포넌트의 key 가 같다. (1차 오류) 이 상태에서 회원 유형을 (B)로 바꾸면, (b) 컴포넌트가 생기지만 (a)와 (aa) 컴포넌트는 사라지지 않는다. 왜? (b) 컴포넌트와 key 가 같아서 이전 DOM과 다를게 없으니까! 또 다시 회원 유형을 (A)로 바꾸면 이전 오류들 + (b)컴포넌트와도 같은 key 값... 으로 계속 쌓이게 된다. 차라리 이런 경우라면 key 값을 없애는 것도 방법이겠다. 리액트에서 key값을 부여하는 경우는, 같은 컴포넌트 (함수형) 클래스를 사용해 여러 자식 컴포넌트를 만들때이기 때문에, 위 상황과는 맞지 않을것 같다.

 

-- 프론트엔드는 너무 어려워 @-@

 

 

 

참고 블로그

https://amkorousagi-money.tistory.com/entry/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BB%B4%ED%8F%AC%ED%84%B4%ED%8A%B8-%EC%95%88-%EB%B0%94%EB%80%9Creact-component-not-change