React Components, Elements, and Instances 번역글

Boaz Hwang
11 min readMar 17, 2022

--

Managing the Instances

기존 UI model(OOP)

class Form extends TraditionalObjectOrientedView {
render() {
// Read some data passed to the view
const { isSubmitted, buttonText } = this.attrs;
if (!isSubmitted && !this.button) {
// Form is not yet submitted. Create the button!
this.button = new Button({
children: buttonText,
color: 'blue'
});
this.el.appendChild(this.button.el);
}
if (this.button) {
// The button is visible. Update its text!
this.button.attrs.children = buttonText;
this.button.render();
}
if (isSubmitted && this.button) {
// Form was submitted. Destroy the button!
this.el.removeChild(this.button.el);
this.button.destroy();
}
if (isSubmitted && !this.message) {
// Form was submitted. Show the success message!
this.message = new Message({ text: 'Success!' });
this.el.appendChild(this.message.el);
}
}
}
  • Button class component → instance(각자 local state, own properties 가짐)
  • Form 이 render() 에서 new Button() 호출 instance 를 appendChild 호출하여 render
  • isSubmitted 와 this.button, this.message 체크해서 각 children 을 create, update, destroy

한계점

각 component 는 DOM node 주소와, 자식 component 의 instance 주소를 보관해야하며, 시의 적절하게 각각을 create, update, desotry 해야 함

  • 관리할 컴포넌트 늘어나면 component 코드의 복잡도 증가
  • 자식 component 에게 부모 component 가 직접 접근하므로 decouple 하기 어려움

Elements Describe the Trees

React 는 element 를 활용하는 것이 기존 UI model 과 차이점

Elements

  • is plain object describing component instance, DOM node and its desired properties
  • is not instance, just tell React what you want to see on the screen
  • is immutable description object with two fields(type: string | ReactClass, props: object)

React DOM elements

{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
<button class='button button-blue'>
<b>
OK!
</b>
</button>
  • type: string(tag name)
  • props: tag’s attributes
  • just objects, so lighter than DOM elements(not objects)
  • don’t need to be parsed, easy to traverse

React Component elements

{
type: Button,
props: {
color: 'blue',
children: 'OK!'
}
}
  • type: Function Or Class(React component)
  • props: React component props

An element describing a component is also an element, just like an element describing the DOM node. They can be nested and mixed with each other. (element 에 의해 기존의 DOM node 와 React component 를 mixed, nested 한 구조가 가능해짐)

→ 그 결과, component 끼리 decoupled 가 됨(컴포넌트끼리 is-a, has-a 관계로 표현 가능해짐)

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>
</div>
);

Components Encapsulate Element Trees

React 가 type 값이 class or functional 인 element(React component element)를 만나면

  1. type 값을 보고, 해당 component 함수에게 element 를 return 받는다
  2. return 받은 element 의 type 값이 tag name 인 element(DOM element)를 만날때까지 1번으로 돌아감
{
type: Button,
props: {
color: 'blue',
children: 'OK!'
}
}
// React는 Button을 만나면 component에게 물어봐서 아래 DOM element 를 return 받음
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}

React 는 모든 React Component elements 가 React DOM elements 를 return 할때까지 위 과정 반복

모든 elements 가 가진 DOM elements 를 알게 됨 → React 가 해당 DOM elements 들을 적절한 때에 create, update, destroy

따라서 기존에 Form UI modeling 을 아래와 같이 간단하게 구현할 수 있게 됨

const Form = ({ isSubmitted, buttonText }) => {
if (isSubmitted) {
// Form submitted! Return a message element.
return {
type: Message,
props: {
text: 'Success!'
}
};
}
// Form is still visible! Return a button element.
return {
type: Button,
props: {
children: buttonText,
color: 'blue'
}
};
};

React functional component 는 Props 를 받아서 element 를 return 하는 javascript function

The returned element tree can contain both elements describing DOM nodes, and elements describing other components. This lets you compose independent parts of UI without relying on their internal DOM structure. (React element 를 활용하여, 기존에 DOM structure 을 모두 활용하지 않고, 필요한 정보만 독립적으로 UI 를 관리할 수 있게 됨)

Component 가 return 한 element 를 활용해서 DOM Trees 를 encapsulate

Components Can Be Classes or Functions

이 부분은 생략(Functional component 의 기능이 추가 되어서 Class component 와 동등해짐)

Top-Down Reconciliation

ReactDOM.render({
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}, document.getElementById('root'));

위 함수 호출 시, React 는 Form component 에게 props 를 전달하며 return element 를 요청

Form → Button → DOM node element(button) 순서로 return element 진행

// React: You told me this...
{
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}
// React: ...And Form told me this...
{
type: Button,
props: {
children: 'OK!',
color: 'blue'
}
}
// React: ...and Button told me this! I guess I'm done.
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
  • ReactDom.render(), setState() 호출 시 React call reconcilation reconcilation 이 끝나면 React knows resulting DOM tree renderer(e.g. react-dom) 는 필수적인 최소한의 변화를 DOM node 업데이트에 적용
  • 위와 같은 점진적 변화 덕분에 쉽게 optimization 가능 props 가 immutable 이면 change 계산이 더 빨라짐
  • React 가 class component 의 Instance 를 만들어줌(직접 생성 X) Parrent component instance 가 child component instance 에 직접 접근 하려면 ref 를 활용하는 방법이 있지만, 위 맥락에서 렌더링 최적화를 방해하기에 필수적인 상황(form item 에 focus 를 찾아야 한다거나 등) 제외하고 안하는게 좋음
  • Instances 는 React 가 관리하므로, class component 구현시 OOP 스럽게 짜면 되는 정도(따로 instance 에 대해 신경 쓸 필요 X)

Summary

  • element 는 DOM Tree 생성에 필요한 정보를 담은 object 다. React DOM node element, React Component element 두 종류. element 는 property 로 다른 element 를 가질 수 있다 → DOM node 와 React component 를 mixed, nested 가능하게 함
  • component 는 props → element 하는 function
  • parent component 가 return 한 element 의 type 이 child component 이름일 때, props 는 해당 child component 의 input(props) 가 된다 → props 는 1 way flow
  • instance 는 class component 에서의 this
  • instance 를 직접 생성할 필요 X → React 가 해줌
  • React.createElement(), JSX, React.createFactory() → return element

--

--