TIL: 리액트 컴포넌트, 앨리먼트 인스턴스 정리
인스턴스 관리하기
a. 기존 모델 (OOP)
-newButton이라는 클래스를 호출해 인스턴스를 생성, 할당 append Child를 통해 돔에 마운트
class Form extends TraditinalObjectOrientedView {
render() {
const { isSubmitted, buttonText } = this.attrs;
if (!isSubmitted && !this.button) {
this.button = new Button ({
children: buttonText,
});
this.el.appendChild(this.button.el);
}
}
버튼이 있는경우, 혹은 isSubmitted 인 경우 등등
removeChild하거나 다시 어펜드 하기로 조작함
if (this.button) {
this.button.attrs.children = buttonText;
this.button.render();
}
if (isSubmitted && this.button) {
this.el.removeChild(this.button.el);
this.button.destroy();
}
if (isSubmitted && !this.message) {
this.message = new Message({ text: 'Success !' });
this.el.appendCHild(this.message.el);
}
한계점 수작업으로 리무브와 어펜드 등등 코드를 작성해야 하는 한계가 있었음 관리할 코드 증가 부모컴포넌트가 자식에 직접 접근하므로 디커플링을 하기 어려워짐.
b. 엘리먼트는 트리를 묘사함
리액트는 엘리먼트를 활용하는 것이 기존 UI모델과 다름
- 엘리먼트
1) 엘리먼트는 컴포넌트 인스턴스를 묘사하는 기본 객체다.
인스턴스는 아니고 화면에 그리라고 말해주는 애다. (돔트리에 대한 정보 가지고 있음)
2) type: string | ReactClass, props: immutable한 object 프로퍼티를 가지고 있음 어떨때 string? 클래스? 할당?!
1. 리액트 돔 앨리먼트
type에 string이 할당되어 있는 경우 아래의 예시를 보면 button은 html태그임
props에는 className, children등 어트리뷰트 들이 할당
{
type : 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
<button class= 'button button-blue' >
<b>
OK!
</b>
</button>
2. 리액트 컴포넌트 엘리먼트
type에 React Function or Class가 할당되어 있는 경우
props에 어떻게 해야 돔트리에서 보이게 될지 정보 담고있음
{
type: Button,
props: {
color: 'blue'.
children: 'OK!'
}
}
컴포넌트와 돔엘리먼트와 같은 위계에서 관리 될 수 있게 됨 컴포넌트 끼리 decoupled가 될 수 있게 됨
예시 : DeleteAccount컴포넌트
const DeleteAccount = () => ({
type : 'div',
props: {
children: [{
type: 'p',
props {
children: 'Are you sure? '
}
}, {
type: DangerButton,
props: {
children: 'Yep'
}
}, {
type: Button,
props: {
color: 'blue',
children: 'Cancel'
}
}]
});
const DeleteAccount = () => {
<div>
<p> Are you sure? </p>
<DangerButton> Yep </DangerButton>
<Button color='blue'>Cancel</Button>
type은 div이고 children에 여러가지 앨리먼트들을 가지고 있음
decoupled가 될 수 있음
DeleteAccount컴포넌트에서 Button이라는 Class 밖에 할당된 것이 없으므로
(언제 rendering? destroy?에대한 정보는 없음을 알 수 있음)
엘리먼트들을 트리구조로 리턴해 주게 되는데 트리 안에는 돔트리에 전달할 정보만 캡슐레이션 되어있음
컴포넌트는 엘리먼트 트리들을 요약(encapsulation) 함
(기존 OOP모델의 한계극복!!) React가 type값이 class or functional인 element를 만나면
1. type값을 보고 해당 컴포넌트 함수에게 element를 return받는다.
2. return 받은 element의 type값이 태그네임인 엘리먼트를 만날 때까지 1번으로 돌아감
컴포넌트 트리에 의해 돔트리에 어떤 정보를 전달해 줘야 할지 알게 됨 그래서 create, update, destroy 로직을 다른 곳에서 수행 함
const Form = ({ isSubmitted, buttonText }) => {
if (isSubmitted) {
return {
type: Message,
props: {
text: 'Success!'
}
};
}
return {
type: Button,
props: {
children: buttonText,
color: 'blue'
}
};
}
필요한 정보만 독립적으로 UI를 관리함
c. 탑다운 리컨실레이션
ReactDOM.render({
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}, document.getElementById('root'));
React.DOM함수 호출 시 리액트는 Form에 props를 전달,
return element를 요청
Form → Button → DOM node element(button)순서로 return element진행
{
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}
{
type: Button,
props: {
children: 'OK!',
color: 'Blue'
}
}
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
이 과정을 reconcilation 이라고 함
이것이 끝나게 되면 react는 엘리먼트 트리가 만들어지게되고,
DOM tree에 적용함
renderer는 필수적인 최소한의 변화를 DOM node업데이트에 적용
점진적 변화로 인해 쉽게 최적화가 가능
props가 이뮤터블이라 변화의 계산이 더 빨라지게 됨
리액트가 클래스 컴포넌트의 인스턴스를 만들어줌(우리가 직접 생성하지 않아도 됨)
정리
엘리먼트는 돔트리 생성에 필요한 정보를 담은 object.
리액트 돔 노드 엘리먼트, 리액트 컴포넌트 엘리먼트
앨리먼트는 속성으로 다른 앨리먼트를 가질 수 있음
돔노드와 리액트 컴포넌트를 섞어서, 중첩해서 사용 가능하게 함