리액트는 변경사항이 한가지의 방향으로 흘러간다. 즉, 상태(state)가 변경되면 React가 render 함수를 호출해서 UI가 업데이트 된다.
리액트를 페이스북에서 사용자 인터페이스(UI)를 구축하기 위해 만든 자바스크립트 라이브러리이다. 리액트는 크게 두가지 특징으로 정의해볼 수 있다.
첫번째 특징은, 상태(state)가 변경될 때마다 리액트가 자동으로 어플리케이션 전체를 다시 업데이트를 한다는 것이다. 변경이 될 때마다 수동으로 다시 업데이트 하지 않아도 되며, 상태(state)에 맞게 render 함수가 어떻게 표기될건지만 정의하면 React가 알아서 자동으로 render를 호출해준다.
두번째 특징은, 리액트만의 가상의 돔(버츄얼돔)이 있다는 것이다. 리액트 내부에 가상의 돔(버츄얼 돔)을 메모리에 보관해놓고 있기 때문에, 업데이트가 일어날 때마다 이전의 돔 트리와 비교-계산해서 실질적으로 업데이트 되는 내용만 DOM Tree에 업데이트를 하게 된다. 게다가 매번 업데이트 하는 것이 아니라, 업데이트 내용을 모아놨다가 한꺼번에 업데이트되기 때문에 성능 역시 빠르게 보장한다는 특징을 가진다.
DOM 구조를 만들기 위한 기존 방식의 컴포넌트 코드
class App {
render() {
const container = document.createElement('div');
const header = document.createElement('header');
const content = document.createElement('p');
const footer = document.createElement('footer');
header.textContent = "Header";
content.textContent = "Some contents";
footer.textContent = "Footer";
container.append(header, content, footer)
}
}
JSX(React의 독자적인 문법)를 사용한 React 컴포넌트 코드
class App extends React.Component {
render() {
return (
<div>
<header>Header</header>
<p>Some contents</p>
<footer>Footer</footer>
</div>
);
}
}
✍🏻 조금 복잡한 웹어플리케이션을 만들 때, M(Model)V(View)C(Controller) 디자인 패턴을 많이들 택하는데, 이 MVC는 각각의 레이어를 나눠서 코딩 해나갈 수 있는 디자인 패턴을 의미한다. 이 중에서도 리액트는 MVC의 View 레이어를 담당하고 있다. (디자인 패턴에 대해서는 나중에 다시 다룰 것이다.🥸)
리액트의 가상돔(Virtual DOM)은 상태(state)가 변경될 때마다 렌더링이 일어나고 업데이트가 되는 비효율적인 방식을 방지하기 위해 등장한 개념이다. 리액트의 컴포넌트는 가상의 돔(Virtual DOM) Tree로 리액트의 메모리에 저장되어 있으며 바로 DOM Tree에 업데이트 되지 않는다. 컴포넌트에 변동 사항이 생겨 render 함수가 호출되면 리액트는 내부적으로 최적화된 '비교 알고리즘'을 이용하여 이전의 DOM Tree와 비교해서 실질적으로 어떤 부분이 업데이트 되어야 하는지 파악하고, 필요한 부분만 DOM Tree에 업데이트를 한다. render 함수가 여러번 업데이트-호출이 되어도 실질적으로 보여지는 데이터가 변동되지 않으면, 이 DOM Tree에는 전혀 영향을 주지 않기에 render 함수가 여러번 호출이 되어도 React의 성능에 큰 영향을 끼치지 않는다.
✍🏻 가상 DOM은 결국 DOM 구조를 일반적인 자바스크립트 객체로 추상화한 것이다. 따라서 JSX 코드는 Babel 과 같은 트랜스파일러를 통해 변환된다.
리액트는 가상 돔(버츄얼 돔)을 통해 자동으로 빠르게 UI를 업데이트 할 수 있다는 장점이 있다. 무엇보다도 페이스북의 지속적인 관리와 함께 생태계가 활성화 되어 있고, 문서화 역시 잘되어 있다. 문서화가 잘 만들어져있고, 커뮤니티가 활성화되어 있다는 뜻은 앞으로 내가 겪을 어떤 문제를 해결하는데 가능성이 높아진다는 뜻일 것이다. 그리고 이 때문에 많은 기업과 개발자들이 리액트를 선택한다.
집을 만드는 과정을 예를 들어보자면, 프레임워크(앵귤러)는 이미 집의 구조나 철제들이 완성된 완성품에 더 가깝기 때문에 정해진 골격 안에서 내가 원하는 기능을 구현해야 한다. 반면 리액트와 같은 라이브러리인 경우에는 내가 원하는 재료를 골라서 내 취향과 입맛에 맞게 집을 지을 수 있고, 내가 필요한 기능에 따라서 라이브러리를 골라서 사용할 수 있다는 차이점이 있다.
컴포넌트는 한가지 기능을 수행하는 UI 단위를 말한다. 독립적이고, 재사용이 가능하다는 특징이 있다.
JSX 문법을 언뜻 봤을 때 HTML 문법과 굉장히 유사합니다. 그러나 JSX 코드는 브라우저에서 알아들을 수 없는 문법이기에 Babel과 같은 트랜스파일러를 통해 React element를 생성하는 코드로 변경됩니다. React.createElement() 함수를 사용해 가상 DOM 객체를 만드는 형태가 됩니다.
리액트에서 직접적으로 state를 변경해서 렌더링할 경우 업데이트한 값이 변경되어 렌더링되지 않는다. 이는 state의 저장방식이 객체이기 때문인데, 값이 변경되었다는 걸 인지하기 위해서 React는 객체로 저장된 state를 비교 연산한다. 비교하는 판단의 근거가 객체의 메모리의 참조값(레퍼런스) 이기 때문에 직접 state를 변경할 경우 변경이 안된 것으로 판단하고 업데이트하여 렌더링하지 않게 되는 것이다. 그렇기 때문에 새로운 객체를 만들어 값을 반환하는 useState()
함수를 사용하여 상태를 업데이트해야 한다.
가장 중요한 것은 컴포넌트가 렌더링 되는 것을 최소화해야 합니다.useCallback
이나 useMemo
와 같은 훅을 사용해서 의존성이 변경되었을 때 메모이제이션된 값을 계산해서 변경하도록 하여, 컴포넌트의 불필요한 렌더링을 줄여야 한다.
추가적으로 알아야 할 지식 : memoization(메모이징)
✍🏻 memoization(메모이제이션) : 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복적인 수행을 방지하여 프로그램 실행 속도를 빠르게 하는 기술. 이전에 수행한 연산의 결과값을 저장해두고 동일한 입력이 들어왔을 때, 재활용하는 프로그래밍 기법을 말한다. 메모이징 기법을 적절히 적용하면 중복되는 연산을 피할 수 있기 때문에 메모리를 조금 더 쓰더라도 어플리케이션의 성능을 최적화할 수 있다.
React Virtual DOM Explained in Simple English
Components in React
[기초부터 완성까지, 프런트엔드] - 이재성, 한정 지음