참고
리액트 공식문서
Babel은 JSX를
React.createElement()호출로 컴파일합니다
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
해당 JSX 문법으로 작성 된걸 Babel에서는
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
React.createElement() 로 바꿔서 컴파일 해준다는 의미이다
-> 다시 말해 JSX는 React.createElement() 를 조금 편하게 호출할 수 있는 syntax sugar일 뿐
기본적으로 React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프 하므로, 애플리케이션에서 명시적으로 작성되지 않은 내용은 주입되지 않습니다. 모든 항목은 렌더링 되기 전에 문자열로 변환됩니다. 이런 특성으로 인해 XSS (cross-site-scripting) 공격을 방지할 수 있습니다.
React.createElement()일반 JS에서도 document.createElement() 가 존재하는데, 둘의 차이는 뭘까?
const element = document.createElement('div')
element instanceof HTMLElement // true
document.createElement() 의 결과는 HTMLElement 이다
생성된 element를 직접 DOM에 삽입하여 화면을 그릴 수 있다
const element = React.createElement(type, props, ...children)
하지만 React.createElement() 로 생성된 것은 객체이다
리액트에서는 해당 객체를 React 엘리먼트 라고 하며, 화면에서 보고 싶은 것을 나타내는 표현이라 생각하면 된다. React는 이 객체를 읽어서, DOM을 구성하고 최신 상태로 유지하는 데 사용한다
- 브라우저 DOM 엘리먼트와 달리 React 엘리먼트는 일반 객체이며(plain object) 쉽게 생성할 수 있습니다
- React DOM은 React 엘리먼트와 일치하도록 DOM을 업데이트합니다
CRA로 리액트 개발환경을 생성하게 되면
//index.html
<div id="root"></div>
import { createRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = createRoot(domNode);
root.render(<App/>)
해당 로직이 index.js 같은 파일에 추가되어있는 걸 볼 수 있는데
여기서 createRoot() 와 render() 라는 메서드를 사용하고 있다.
createRoot는 React에서 제공하는 함수 중 하나로,
브라우저의 DOM 노드 내에서 React 컴포넌트를 표시할 수 있는 루트를 생성하는 데 사용됩니다
생성된 Root Node는 React에 의해 해당 노드 내부의 DOM을 관리하는 역할을 합니다.
render()는 전달받은 리액트 엘리먼트들을 해당 Root Node(#root)의 하위 노드에 추가하면서 화면에 보여지게 됩니다
요약하자면 ,
리액트는 createRoot() 를 통해 하나의 DOM Element를 Root Node 로 만든다(하나의 엔트리 포인트(진입점)를 잡는다고 생각하면 이해가 편함)
이후 render() 를 통해 넘겨받은 여러 컴포넌트들을 Root Node 의 하위 노드로 추가해주면서, 화면에 출력된다
Root Node 내부에 존재하는 모든 DOM 엘리먼트는 렌더링이 호출되면 전부 교체되고, 이후의 호출들은 효율적인 갱신을 위해 React의 DOM 비교 알고리즘(Diffing)을 사용합니다.
createRoot()는 넘겨받은 컨테이너 노드를 수정하지 않으며,
오직 그 자식만을 수정합니다.
기존 DOM 노드에 이미 존재하는 자식에 대해 덮어쓰기 없이 컴포넌트를 추가하는 것이 가능할 수도 있습니다.
<html>
<head><title>My app</title></head>
<body>
<nav id="navigation"></nav>
<main>
<p>!이 태그는 리액트로 관리 안해도 됨!</p>
<section id="comments"></section>
</main>
</body>
</html>
const navDomNode = document.getElementById('navigation');
const navRoot = createRoot(navDomNode);
navRoot.render(<Navigation />);
const commentDomNode = document.getElementById('comments');
const commentRoot = createRoot(commentDomNode);
commentRoot.render(<Comments />);
이런 식으로 기존에 존재하는 html은 그대로 유지하고 싶다면, 필요한 태그에만 createRoot 를 사용하는 방법도 가능하다