Intro.
const MyComponent = () => {
return <div>Hello from div</div>;
};
export default MyComponent;
위와 같은 코드가 있습니다.
흔히 부르는 '함수형 컴포넌트' 입니다.
여기서 잠깐 멈춰서 생각해볼것이, 그럼 React Element란 무엇일까요? 그동안은 사실 뭐~ 동음이의어가 아닐까? 하고 넘겼었는데, 어느날 문득 의문이 들어 찾아본 결과 매우 큰 착각임을 깨닫고 글을 써봅니다.
먼저 'Component'란 무엇일까요? React 문서에 따르면 다음과 같습니다.
개념적으로 컴포넌트는 JavaScript 함수와 유사합니다. “props”라고 하는 임의의 입력을 받은 후, 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환합니다.
- Props를 받을 수 있어야함
- React Element를 반환해야함
이렇게 두가지 조건을 만족하는 객체를, React Component라 부릅니다.
여기서 대부분 알다시피 종류로는, Function Component , Class Component 두가지가 있지요.
동일한 컴포넌트들(function,class)을 Babel 트랜스파일러로 변환 시, 다음과 같습니다.
먼저 첫번째 조건인 Props를 받는 처리는 함수형의 경우 인자로써 받으면 되고, 클래스형의 경우 생성자에 주입되어서, 멤버 변수로써 사용됨을 볼 수 있습니다.
재밌는 부분은 두 컴포넌트가 모두 'React.createElement'함수에 코드상 반환되는 html요소들을 매핑하여 반환한다는 점입니다.
이 부분에서, React Element가 createElement함수에 의해 생성됨을 알 수 있습니다.
그러면 React Element란 무엇일까요?
An element is a plain object describing a component instance or DOM node and its desired properties.An element is not an actual instance. Rather, it is a way to tell React what you want to see on the screen. You can’t call any methods on the element. It’s just an immutable description object with two fields: type: (string | ReactClass) and props: Object.
컴포넌트 인스턴스 혹은 DOM 노드, 그리고 그들의 속성을 리액트에게 설명할 수 있는 객체
음.. 개념은 알겠는데, 아무래도 정확하게 눈으로 봐야겠습니다.
이를 확인하기 위해, 함수형 컴포넌트의 실행 결과를 출력해보았습니다.
const Mycomponent = () => <div>123</div>
console.log(Mycomponent())
어? 뭔가 익숙한 프로퍼티들이 보이는군요.
key , ref , props와 같이 익숙한 프로퍼티들도 보이고, $$typeof ,_owner 같이 생소한 프로퍼티들도 보입니다.
일단 key, ref의 경우 특수 프롭이니 props와 분리됨을 알 수 있고,
$$typeof 프로퍼티의 경우 보안적 측면을 위한 요소입니다.(이부분에 대해선 추후 글에 서술 하겠습니다)
type의 경우엔, DOM트리에 표기될 태그이름과, props->children 프로퍼티로 div태그의 자식 요소들에 대한 정보가 명시되어 있습니다. (DOM Node에 대한 정보 표기)
실제로 저희가 컴포넌트를 사용할 때 는, 호출 구문 대신, jsx 문법으로써 사용하지요.
그렇기에 이번에는 <Mycomponent/>를 출력해보겠습니다.
비교를 위해 Mycomponent()또한 같이 출력했습니다.
어? 두가지 변화가 생겼습니다.
일단 props에 있던 chidren이 사라졌습니다.
또한, type프로퍼티가 div -> 컴포넌트 그 자체로 변화하였습니다.
그리고 이외는 동일합니다.
여기서 재밌는 사실을 발견할 수 있는것이, React Element에 어떤 타입을 넣느냐에 따라 Component냐 DOM Node냐를 설명할 수 있다는 점이고, 이러한 구조들을 중첩시킬 수 있습니다. 이것이 React 공식 문서에서 말하는 핵심 아이디어입니다.
그리고 이 특성 때문에, React에서 일반적인 DOM Element, Function Component, Class Component 모두 조합하여 사용할 수 있습니다.
다음과 같이 말이죠.
const Button = () => {
return <button>my button</button>
}
const MyComponent = () => {
return <div> //DOM Node
<Button/> //Function Component
<span>hello My component users</span> //DOM node
</div>
}
<MyComponent/>를 사용시, react는 다음과 같은 과정을 거칩니다.
1. MyComponent가 뭐야? -> DOM node 'div'와 자식 프로퍼티로 Button 과 span을 가져
2. div는 ? -> DOM node네? 패스
3. Button는? -> DOM Node 'button'과 자식 프로퍼티로 텍스트 'my button'을 가져
4. button는? -> DOM Node네? 패스
5. span는? -> DOM Node네? 패스
그리고 이런 과정, 즉 React가 결과적으로 DOM Tree를 완전히 인식하게 하는 과정을 'Reconcilation'라 부릅니다.
(ReactDOM.render() , setState 호출 시, 발생합니다) 그리고 Reconcilation이 끝날 시점에 diffing 알고리즘을 통해 도출된 최소한의 변화 요소들을 DOM Node에 적용합니다. 이 때, React.memo 와 같은 함수들을 이용해, 컴포넌트 트리 탐색 비용을 절감할 수 있습니다.(물론 이 부분에 대해 개발자의 컨트롤이 필요하겠습니다만..)
그렇다면 Component Instance는 무엇일까요?
공식문서에서 직접적으로 발췌하자면 다음과 같습니다.
오직 클래스형 컴포넌트만 컴포넌트 인스턴스를 가지며, 개발자가 직접적으로 생성할 수 없으며, 생성 과정을 리액트가 대신 매니징 해줍니다. ref에 의해 접근 가능합니다.
공식 문서에서 업데이트를 안한다 밝혔기에, (2015년 작) 아마 컴포넌트 인스턴스의 정의가 react hook 이전 클래스형 컴포넌트가 메인인 시점 때의 정의인것 같습니다만, 요즘 기준으로 함수형 컴포넌트 또한 인스턴스를 갖는다 생각해도 될 듯 합니다.
정리하자면, 쉽게 말해, 실질적으로 state가 존재하고, Life cycle을 갖는, 실제 사용하는 객체를 의미합니다.
마지막으로 React Node는 쉽게 말해, React Component로 반환 할 수 있는 '모든 것' 이 React Node입니다.
공식 문서에선 다음과 같이 정의하고 있습니다.
- React Element
- Portal
- 문자열
- 숫자
- 불리언, null , undefined
- React Node 배열
function MyComponent() {
return 42; // It's ok to return a number from component
}
위 코드의 경우, React Node입니다만, React Element는 아닙니다.
Reference :: https://legacy.reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html
'React' 카테고리의 다른 글
Fiber reconciler (outdated) (1) | 2023.09.26 |
---|---|
[React] Reconciliation - (feat, Diffing 알고리즘) (0) | 2023.06.26 |
[React] Pie Chart 만들기 (0) | 2022.12.04 |
[React] Bar chart 만들기 (0) | 2022.12.03 |