어떻게 해야하는지 보다 무엇과 같은지 설명하는 프로그램을 선언형 프로그램이라고 한다.
React 공식페이지에서는 React를 선언형이라고 설명한다.
React가 선언형이라는 것은 무슨 의미일까? 아래 예시를 보면서 확인해보자.
// Hello, World! 화면에 출력하기
// 순수 javaScript 명령형 코드
const root = document.getElementById('root');
const header = document.createElement('h1');
const headerContent = document.createTextNode(
'Hello, World!'
);
header.appendChild(headerContent);
root.appendChild(header);
// React 코드 (선언적인)
const header = <h1>Hello, World!</h2>; // jsx
ReactDOM.render(header, document.getElementById('root'));
명령형으로 작성된 코드의 경우 Hello, World!를 출력하기 위해 컴퓨터가 수행하는 절차를 일일히 코드로 작성해주어야 한다.
반면, React 코드의 경우 내가 UI을 선언하고 render 함수를 호출하면 React가 알아서 절차를 수행해 화면에 출력된다. 즉, 화면에 어떻게
그려야할지는 React 내부에 숨겨져 잘 추상화되어 있다.
이 덕분에 다음과 같은 이점을 얻는다.
하지만, React의 선언적인 특성의 진가는 UI 수정시에 나타난다.
// Hello World!를 Hello로 변경하고 싶다면?
// 순수 javaScript 명령형 코드
const header = document.getElementById('header') // id가 존재한다고 가정
header.textContent = 'Hello';
// React 코드 (선언적인)
const header = <h1>Hello</h2>; // jsx
ReactDOM.render(header, document.getElementById('root'));
명령형 코드는 기존 렌더링된 UI에서 일부 속성을 계속 수정한다. 따라서 동일한 Element를 수정하는 Event가 많을 수록 화면이 어떻게 그려질지 예측하기 어려워진다.
반면, React의 경우 어떻게 변경해야하는 신경 쓸 필요 없이 새로 보여줄 결과 ReactElement 를 선언하고 render 하면된다.
하지만, 새로운 결과를 선언하고 render한다고 해서 기존 element가 완전히 제거되고 새로운 element가 이를 대체한다면, 다음과 같은 문제가 발생한다.
⇒ React는 이런 문제를 해결하기 위해 Virtual DOM과 reconciliation이라는 개념을 도입했다.
React는 선언적으로 UI를 구성하고 업데이트 할 수 있도록 도와주는 라이브러리이다. 이 결과 다음과 같은 장점을 얻는다.
하지만 UI 라이브러리/프레임워크에서 React가 선언적이라는 특징을 독점하는 것은 아니다.
많은 라이브러리가 선언적 프로그래밍을 지향하고, 이를 달성하기 각자의 해결책을 도입하는 것으로 보인다.
(React: Virtual DOM/Reconciliation, Svelte: Compiler-centric 등)