컴포넌트들이 화면에 보여지기전에, 그 컴포넌트들은 반드시 리액트에 의해서 렌더링이 되어야합니다.
이 렌더링 과정을 이해하는 것은 어떻게 당신이 작성한 코드가 동작하는지, 그리고 그 코드들의 동작 원리를 설명하는데에 도움이 됩니다.
당신은 이 글에서
에 대해서 배우게 될 것입니다.
한번 당신의 컴포넌트들이 부엌에서 맛있는 요리를 만들고 있는 요리사들이라고 상상해보세요.
이 단계에서, 리액트는 고객들로부터 주문을 받아서, 주문 받은 것들을 고객들에게 가져다주는 웨이터입니다.
요청을 받아서 UI를 전달시켜주는 이 과정은 3가지의 단계가 있습니다.
컴포넌트가 렌더링 되는데에는 2가지의 이유가 있습니다.
당신이 당신의 어플리케이션을 처음 동작시켰을때, 초기 렌더링이 진행됩니다.
프레임워크들이나 sandbox 들은 이 코드를 숨기지만, 이것은 타겟이 되는 DOM 노드와 함께 createRoot를 호출하고, 당신의 컴포넌트와 함께 render메서드를 호출합니다.
import Image from './Image.js';
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'))
root.render(<Image />);
export default function Image() {
return (
<img
src="https://i.imgur.com/ZF6s192.jpg"
alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals"
/>
);
}
root.render()부분을 주석처리하면 컴포넌트가 사라지는것을 볼 수 있습니다.
컴포넌트가 초기에 렌더링 된 후에도, 당신은 set 함수를 통해서 state들을 업데이트 함으로써 더 많은 렌더링들을 만들어 낼 수 있습니다.
당신의 컴포넌트의 state를 업데이트 하는것은 자동으로 렌더링을 하도록 합니다.
(당신은 레스토랑의 손님이 그들의 첫번째 주문 후에, 그들의 배고픔이나 목마름에 따라서 차나 디저트나 다른것들을 주문하는것을 상상해볼 수 있습니다.)
당신이 렌더링을 유발한 후에, 리액트는 브라우저 화면에 무엇을 띄어야 하는지 알기 위해서 당신의 컴포넌트들을 호출합니다.
"렌더링"은 리액트가 당신의 컴포넌트들을 호출하는 것입니다.
이 과정은 재귀적입니다. 만약에 업데이트 된 컴포넌트가 다른 컴포넌트들을 리턴한다면, 리액트는 리턴 된 컴포넌트를 렌더링 할 것이고, 만약에 리턴된 컴포넌트 안에 또 다른 컴포넌트가 리턴된다면, 리액트는 또 그 컴포넌트를 렌더링 할 것입니다.
이 과정은 중첩된 컴포넌트들이 더이상 존재하지 않을때까지, 그리고 리액트가 브라우저 화면에 무엇을 띄어야 하는지 정확하게 알때까지 계속 될 것입니다.
밑의 예에서, 리액트는 Gallery 와 Image 컴포넌트를 여러번 호출할 것입니다.
export default function Gallery() {
return (
<section>
<h1>Inspiring Sculptures</h1>
<Image />
<Image />
<Image />
</section>
);
}
function Image() {
return (
<img
src="https://i.imgur.com/ZF6s192.jpg"
alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals"
/>
);
}
import Gallery from './Gallery.js';
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'))
root.render(<Gallery />);
렌더링은 항상 순수한 계산이어야 합니다. Keeping Components Pure
같은 인풋일때, 같은 결과값이어야 합니다. 같은 인풋값이 주어졌을때, 컴포넌트들은 항상 같은 JSX를 리턴해야 합니다. (만약 어떠한 사람이 토마토를 주문했다면, 주문한 사람은 샐러드나 양파를 받으면 안됩니다.)
항상 독립적으로 생각해야 합니다. 렌더링 전에 존재했던 변수들이나 어떠한 객체들을 변경 시키면 안됩니다. (한 사람의 주문이 다른사람의 주문을 변경시키면 안됩니다.)
그렇지 않으면, 당신의 코드량이 증가함에 따라서 예상치 못한 에러들을 직면할 수 있습니다.
"Strict Mode" 에서 개발을 할때, 리액트는 각각 컴포넌트들을 2번씩 호출하는데, 이것은 에러를 유발시키는 컴포넌트들에 의해 발생한 실수들을 발견하는데에 도움을 줍니다.
너의 컴포넌트들을 렌더링 한 후에, 리액트는 DOM을 수정합니다.
초기 렌더링에서는, 리액트는 화면에 생성된 모든 DOM 노드들을 띄우기 위해 appendChild라는 DOM API를 사용할 것입니다.
리렌더링에서는, 리액트는 최신의 렌더링된 결과물과 DOM을 일치시키기 위해서 최소한의 필수적인 동작들(이 동작들은 렌더링이 되는 동안 계산이 되었습니다.)을 적용합니다.
리액트는 렌더링 과정에서 차이점이 발견 됐을때만 DOM 노드들을 변화시킵니다.
예를 들어서, 부모 컴포넌트로부터 매 초마다 변경되는 prop을 리렌더링 하는 컴포넌트가 있다고 가정해봅시다.
당신이 input 태그 안에 값을 입력함으로써 그 값을 업데이트 할수 있지만, 컴포넌트가 리렌더링 될때 해당 text가 사라지지 않는것에 주목하셔야 합니다.
export default function Clock({ time }) {
return (
<>
<h1>{time}</h1>
<input />
</>
);
}
이것은 리액트가 오직 h1 태그 안에 있는 time 변수만을 업데이트 하기 때문에 이렇게 동작합니다.
input 태그가 저번의 위치와 같은 곳에서 나타나므로, 리액트는 input 태그 안에 있는 값을 건드리지 않는 것입니다.
렌더링이 끝나고, 리액트가 DOM을 업데이트 한 후에, 브라우저는 브라우저 화면을 리페인팅 합니다.
이 과정이 "브라우저 렌더링"이라고 알려졌지만, 우리는 이 공식문서 설명 내에서 혼란을 피하기 위해서 페인팅이라고 표현하겠습니다.
당신의 컴포넌트 내에서 실수를 발견하기 위해서 "Strict Mode"를 사용할 수 있습니다.
리액트는 렌더링 전의 모습과 렌더링된 결과물이 같다면 DOM을 조작하지 않습니다.