본문 바로가기
개발개발/Date-project

조건부 렌더링 - 비정상적인 버튼 동작 발생 원인 / 휴리스틱 알고리즘 / key prop의 중요성

by yelimu 2025. 4. 21.

지난 번에 올렸던 버그와 관련하여, 임시로는 해결했지만? 근본적인 해결을 하지 못한채 지나갔었다.

상태에 따라 두 종류(type = "button" / "submit")의 버튼을 조건부 렌더링하는데, UI에는 문제 없지만 기능에 문제가 있었다.

폼의 전체 필드가 채워져있는 경우에 type="button"을 눌렀을때 submit이 작동하는 문제였다.

<form>

isAccountPart ? <AccountSection/> : <InfoSection/> --- 상태에 따라 조건부 렌더링으로, 두 단계로 나눠 폼 작성

<button>이전</button>
isAccountPart ? <button type="button">다음</button> : <button type="submit">제출</button>  

</form>

https://memoryelim.tistory.com/316

 

submit 버튼이 아닌데 submit 되는 버그

아래와 같이 폼의 모든 필드가 채워졌을때 [이전] 버튼 눌러서 이동한 뒤에 [다음] 을 누르면 제출이 이루어진다.[완료] 버튼을 눌렀을때만 제출이 되어야한다.(현재는 제출 버튼 클릭 이벤트에

memoryelim.tistory.com

 

그 원인으로 예상되는 바가 바로 리액트의 휴리스틱 알고리즘이다.

 

리액트가 DOM을 비교하는 방법

 

React에서의 DOM 비교 최적화: Virtual DOM과 휴리스틱 알고리즘

🔑Writing Key Point in Posting💡 알고리즘 시간 복잡도: 왜 중요할까?📃 우리는 소프트웨어를 만들 때 속도가 중요한데, 그때 사용하는 개념이 바로 시간 복잡도입니다. 시간 복잡도는 프로그램이

jelong.tistory.com

https://puterism.com/react-key/

(왜 썸네일 생성이 안되지)

 

 

 

리액트는 휴리스틱 알고리즘을 채택하여 변경된 node를 파악하고, 이를 통해 낮은 시간 복잡도로 성능을 최적화하였다.

 

배열을 순회하면서 .map 메서드를 사용하여 요소를 반복해서 렌더링할때 key prop이 필수로 요구되는데, 

변경(추가, 삭제, 업데이트)되는 자식 요소를 key 로 구분하기 위함이다. 

 

그런데 내 경우에는 map을 사용해서 반복되는 요소는 아니지만, 왜 이런 버그가 발생한걸까?

 

  • 지피티의 답변
  • React는 조건부 렌더링으로 컴포넌트를 바꿀 때, "같은 위치에 있는 DOM"이라고 판단하면 기존 엘리먼트를 재사용하려고 합니다.
  • key가 없으면 React는 <button> 엘리먼트를 재사용하게 되는데, 이때 type="submit" 속성이 이전 렌더링에서 남아있을 수 있습니다.

즉 리액트가 다른 두개의 요소를 같은 엘리먼트라고 인식해서 비정상적인 동작이 일어난 것이다.

아래와 같이 key prop을 추가하니 해결이 되었다.  

return (

<form>

isAccountPart ? <AccountSection/> : <InfoSection/> --- 상태에 따라 조건부 렌더링으로, 두 단계로 나눠 폼 작성

<button>이전</button>
isAccountPart ? <button key="next" type="button">다음</button> : <button key="submit" type="submit">제출</button>  

</form>
)

 

사용자가 제출 의도 없이, 작성한 폼을 살펴보려고 폼을 이동하며 버튼을 눌렀을때 제출이 된다면 굉장히 당황스러울 것이다.

보통은 제출 후 페이지 이동이 이뤄지기 때문이다.

그렇지 않더라도, 경우에 따라 이후에 제출이 정상적으로 이루어지지 않을 수 있다. (중복 제출 등)

만약 그 사이에 내용을 수정하는 경우가 발생한다면 사용자가 제출했다고 인식한 내용과 다른 내용이 서버에는 전달될 것이다.

지금까지 이런 디테일한 부분을 확인해보지 못했던거같은데 실제 유저를 확보한 서비스였다면 알게 모르게 문제가 발생하고 있었을것이라는 생각에 좀 아찔하다. 

 

그리고 key로 적절히 사용할게 없어서 crypto.randomUUID()를 사용한 경우도 몇 번 있었는데, 이는 매 번 새로운 문자열을 반환하므로 key prop을 지정하는 의미(변경되는 요소만 구분하여 리렌더함으로써 성능 최적화)가 사라지는, 좋지 않은 방법이라고 한다.