가끔 리액트 jsx에서 인라인 스타일을 사용할 때가 있었다.
...
return <div style={{marginTop: '10px'}}>hello!</div>
이러한 인라인 스타일 방식을 사용하면 리액트에서 리렌더링이 발생 할 수 있다고 한다.
그 전에 리액트의 기본 동작 방식을 설명하고 넘어가자
리액트는 컴포넌트 내에 스테이트가 변경된 경우에는, 리액트는 해당 컴포넌트를 dirty
하다고 표시하고 batch
에 추가한다.
그리고 Virtual Dom 엘리먼트와 실제 브라우저에 등록되어있는 DOM 엘리먼트를 비교/순회하며 dirty 체크된 엘리먼트들을 처리한다.
이것을 처리하는 과정에서 속성 값만 변한 경우에는 속성 값만 업데이트하고, 해당 엘리먼트의 태그 혹은 컴포넌트가 변경된 경우라면 해당 노드를 포함한 하위의 모든 노드를 언마운트(제거)한 뒤에 새로운 virtualDom으로 대체한다.
이렇게 자신의 가상 돔 트리를 순회하며 변경사항을 업데이트 하는 것이 리액트의 핵심 디핑 알고리즘이다.
인라인 스타일은 객체를 값으로 준다.
자바스크립트에서 속성이 같은 객체를 ===
연산자로 비교하면
false
가 출력된다.
{} === {} // output false
그 이유는 객체는 모두 참조값이기 때문에 참조 주소가 달라 서로 다르다고 인식한다.
여기서 문제가 출발된다.
앞서 설명하였듯 컴포넌트 내에 스테이트가 변경되었을 때
버츄얼 돔을 그리고 서로 순회하여 변경사항을 업데이트 한다.
return 문에 적힌 모든 코드는 버츄얼 돔이다.
여기서 새롭게 변경된 컴포넌트는 내부에 인라인 스타일 객체도 새롭게 리턴 되어 버츄얼돔에서 변경된 값으로 또 인식되어 리렌더 되버린다.
리액트를 사용할 때에는 인라인 스타일을 지양하고,
귀찮더라도 css 작성을 따로 해주거나,
style 객체 자체를 useMemo를 이용해 메모리제이션 해주는게 좋다.