웹상의 UI를 구축하기위한 javascript 라이브러리
트리를 비교하고 변경사항을 적용하는 동작으로 Diffing Algorithm, 자식 list간 key비교를 통해 빠르게 변경된 부분을 찾아, 변경사항을 트리에 반영한다.
Diffing Algorithm
O(n)의 시간복잡도을 통해 효과적으로 UI를 갱신할 수 있는 알고리즘이다. 비교를 수행할 때 두 엘리먼트 트리의 루트부터 비교를 시작한다. 재귀적으로 비교하다보면 아래와 같이 4가지 케이스를 만날 수 있는데, 각 케이스에 대해서 다음과 같이 처리한다.
<div>
<Counter />
</div>
<span>
<Counter />
</span>
<div className="open" style={{ backgroundColor: '#1995C0' }} />
<div className="close" style={{ backgroundColor: '#1995C0', display: 'none' }} />
자식 list 비교
React 가장 핵심은 상태 관리가 아닌가 싶다. 우리가 React와 같은 라이브러리를 사용하는 이유가 상태를 지지고 볶아서 사용자가 보기 쉽게하기 위함이기 때문이다. 또한 사용자의 상호작용이 일어나면 상태를 변화시켜 UI에 변화를 주는 것이 필요하다.
이를 이해하면 React가 어떻게 상태변경을 실제 DOM에 반영을 하는지, 그리고 왜 렌더링 최적화가 필요한지에 대해 알 수 있게 될 것이다.
크게 3가지 과정 Trigger
=> Render
=> Commit
을 거쳐 진행된다.
state변경을 통해 render를 트리거한다. 컴포넌트에서 setState
함수를 이용해 상태를 변경하여 리렌더링을 발생시키는 과정이다.
react 단에서 변경이 발생한 컴포넌트를 호출한다.
초기 렌더링이라면 컴포넌트 트리의 root부터 렌더링하고, 이후에 리렌더링이 트리거된 지점부터 컴포넌트를 호출하며 이를 재귀적으로 수행한다.
이 과정에서 변경이 발생한 부분을 파악하고, 해당 정보를 다음 단계인 Commit에서 활용한다.
Optimizing
react 단에서 변경 사항을 실제 DOM에 반영하는 과정이다. 초기 렌더링 시에는 appendChild
를 통해 모든 돔 노드를 추가한다. 이후 렌더링 시에는 최소한 연산을 통해 DOM을 업데이트하기위해, Render
과정에서 파악한 변경된 부분만을 실제 DOM에 반영한다.
React only changes the DOM nodes if there’s a difference between renders. - React 공식문서
세 단계의 과정이 끝나면 브라우저 렌더링을 통해 최종적으로 사용자가 보는 브라우저 화면에 렌더링하게된다.
function Product({ productId }) {
return <Review productId={productId}/>
}
function ProductList () {
const [product, setProduct] = useState();
return {products.map((product) => <Product productId={product.productId} />)}
}
createElement
로 변환된다. 즉 JSX문법은 React.createElement의 Syntactic Sugar라고할 수 있다.아래와 같이 JSX 문법을 사용하고 트랜스파일 한 결과를 비교하면, 컴포넌트 코드 작성 시 해당 문법으로 우리가 더 생산성있게 구현할 수 있음을 느낄 수 있다.
import App from './src/components/App.js'
function Component() {
return <div>hello!</div>
}
import App from './src/components/App.js';
function Component() {
return /*#__PURE__*/React.createElement("div", null, "hello!");
}
데이터는 아래로 흐릅니다 - React legacy 공식문서
재조정(Reconciliation) - React legacy 공식문서
Redner and Commit - React 공식문서