React의 본질은 UI 라이브러리다.
그리고 React의 핵심은 Component다.
React는 Component를 사용하여 UI를 효과적으로 구성하며, 이에 대한 Update 역시 Component를 통해 진행한다.
React의 작동 원리를 이해하기 위해서는 먼저 알아두어야 할 점이 있다.
React 자체는, Web을 모르며 Browser와는 전혀 관계가 없다는 것이다.
실제로 Browser의 화면을 구성하는 것은 React-DOM이며 React-DOM은 Web에 대한 Interface다.
React는 Component를 어떻게 다루는지에 대해 집중하고,
React-Dom은 Component에 어떤 HTML 요소들이 포함되어 있는지,
컴포넌트 내부에 어떤 허구적인 요소들이 있는지 탐색한다.
이는 실제 HTML 요소들을 화면에 표시해주는 역할을 하는 것이 React-DOM이기 떄문이다.
React는 Component 관리에 대해 집중한다고 하였는데, React가 UI를 구성하기 위해 하는 일은 다음과 같다
- Component 관리
- State object 관리
- 다른 Object의 State와 Component가 바뀌어야 하는지를 확인.
- Component의 내부 데이터가 변경 된 뒤, 변경 전후 State 확인
React는 위와 같이 관리하는 항목에서 변경 내용이 생긴다면,
화면에 표시되어야 할 정보를 React-DOM에 전달한다.
다시 한 번 강조하자면, React-DOM은 Browser의 일부인 실제 DOM에 대한 작업을 하며, 사용자가 보고 있는 화면을 보여주는 역할을 한다.
React가 관리하는 내용 중 핵심 기능은 다음과 같다.
- Props : Component에 전달하는 Data로 Component 구성을 가능하게 해주며, 부모-자식 Component 간 Data를 연결해준다.
- State : Component 내부의 Data를 뜻한다.
- Context : 앱을 구성하는 전체 Component의 Data를 뜻한다.
- Component : 위 기능들의 집합인 Function이다.
Props,State,Context가 변경되면 React는 변경점이 발생되어 적용되는 Component가 화면에 새로운 것을 표시하는 것인지 확인하여 React-DOM에 이를 알려 리액트 DOM이 새로운 화면과 새로운 Component, 그리고 새로운 Rendering을 할 수 있게 알려준다.
그렇다면 React-DOM이 Component의 변경 내용을 전달 받은 뒤, 실제 DOM을 통해 Rendering을 진행할 때, React-DOM은 Brower와 어떻게 서로 통신을 주고 받을까?
React는 Component를 다루며 최종적으로 가상 DOM이라는 개념을 사용한다.
가상 DOM은 어플리케이션이 마지막에 만들어내는 컴포넌트 트리를 결정한다.
Component는 JSX(return문)를 반환하는데, 이때 가상 DOM은 Component 트리의 현재 형태과 최종 형태를 비교한 뒤 트리의 모양을 결정한다.
만약 State가 업데이트 되었다면, 업데이트 정보는 React-DOM으로 전달되어 갱신 전후의 State 변경점을 확인하고, React가 Component 트리를 통해 구성한 가상 DOM과 일치하도록 실제 DOM을 조작하는 방법을 알 수 있게 한다.
React는 Component 함수에 변경이 일어났을 때 컴포넌트 함수를 재실행하고 이후 재평가한다.
조금 더 구체적으로 설명하자면,
- Props,Context,state의 변경사항 발생
- React가 컴포넌트 함수를 재실행 함.
- React가 이를 재평가하게 되는 시스템이다.
여기서 중요한 점은
- Component 함수가 재실행된다고 해서 무조건 재평가로 이어지지 않는다는 점.
- 재평가라는 것이 꼭 DOM을 re-rendering하는 것은 아니라는 점이다.
Component가 담당하는 부분, React가 담당하는 부분, 그리고 실제 DOM이 하는 역할은 구분되어 있으며, 서로 맡은 부분에 충실히 이행한다.
그리고 계속 강조하지만 리액트는 오로지 컴포넌트와 관련된 부분만 신경쓴다.
다시 상기하자면, Component는 state,props,Context가 변경될 때 재평가 되어 Component 함수를 재실행 한다.
그리고 실제 DOM은 React가 구성한 컴포넌트의 이전 상태와 트리 그리고 현재 State간의 차이점을 기반으로 변경이 필요할 때만 업데이트된다.
실제 DOM이 필요한 경우에만 변경된다는 점은 성능 측면에서 매우 중요하다.
현재의 상태를 메모리 안에서 가상 DOM을 통해 비교한다는 것은 간편하고, 자원도 적게 들기 때문이다.
요약하자면, 리액트는 가상 DOM과의 비교를 통해 최종 스냅샷과 현재의 스냅샷을 실제 DOM에 전달하는 구조를 가지며 가상 DOM을 통해 2개의 스냅샷 간의 차이점을 알아낸다.
State가 변경되어 몇가지 추가 요소를 넣어 Component 함수를 실행했다고 가정해보자.
이 경우, 리액트는 변경 전의 스냅샷과 변경 후의 스냅샷간의 차이점을 React-DOM에 보고하고, React-DOM은 실제 DOM을 업데이트하고, 새롭게 추가된 요소를 집어넣는다.
이때 React-DOM은 전체 DOM을 re-rendering하지 않고 변경사항이 적용되어야 할 부분만 변경하거나 추가한다.
function App() {
// 리액트는 State,Props,Context의 변경시에 함수를 재실행하고 재평가한다.
.
const [showParagraph, setShowParagraph] = useState(false);
// 컴포넌트 전체가 재실행되고, 재평가되기에
// 버튼을 클릭할 때 마다 리액트가 console.log를 실행한다.
console.log('App Running');
const toggleParagraphHandler = () => {
setShowParagraph(prev => !prev);
}
// render는 JSX 함수 호출과 같다.
// Component 함수를 호출하여 실행한다는 것은
// 내부에 있는 자식 component도 역시 다시 실행되고 재평가되는 것을 의미한다.
// 자식 컴포넌트는 부모 컴포넌트의 일부이기 때문에,
// 부모 컴포넌트가 변경되면 자식 컴포넌트도 변경되는 것이다.
// 부모-자식간의 컴포넌트의 재실행은 props의 전달과는 상관 없이 이뤄진다.
// 물론 부모 컴포넌트가 재실행된다고 해서, 실제 DOM이 변경된다는 것은 아니다.
// 단지 컴포넌트의 재평가와, 재실행이 일어나는 것이고
// 이는 실제 DOM이 다시 렌더링되거나 변경되는 것이 아니기 때문이다.
return (
// 첫번째 랜더링(초기 랜더링)을 하면서,
// 리액트는 div와 h1 button이 필요하다는 것을 알게 된다.
// paragraph는 처음에 표시되지 않게 해놨기 때문에 첫 랜더링에서는 paragraph를 고려하지 않는다.
// 그리고 마지막 출력을 확인한다.
// 컴포넌트 첫 랜더링에서는 이전 스냅샷은 존재하지 않기에
//차이점을 비교하는 과정에서 div, H1 button이 다시 랜더링 된다.
// 그리고 이 정보가 리액트 DOM으로 전달되어 화면에 렌더링 결과가 표시된다.
// 즉, 실제 DOM에서는 가상 snapshot 간의 "차이점만 반영된다."
<div className="app">
<h1>Hi there!</h1>
// props는 부모에서 자식 컴포넌트로 향한다
// props를 통해 넘겨받은 값은 부모의 상태가 다른 상태로 바뀔 때 바뀐다.
<DemoOutput show={false}/>
<Button onClick={toggleParagraphHandler}>Toggle Paragraph</Button>
</div>
);
}
export default App;
변겅점 오타 있네용
잘 읽었습니다