티스토리 뷰

클래스형 컴포넌트를 작성해보신분들은 Class의 형태로 리액트 컴포넌트를 정의하고 그것을 인스턴스화해서 화면에 컴포넌트를 렌더링 하는 과정을 알고 있을겁니다. 그럼 Elements는 대체 뭘까요?

 

지금까지의 UI 라이브러리들은 자식 컴포넌트의 생성과 제거의 책임을 부모 컴포넌트에게 돌렸습니다. 그래서 부모 컴포넌트의 값이 바뀌면 그 부모컴포넌트에서 자식을 새롭게 갱신하는 작업을 해줬어야 했죠. 부모 컴포넌트는 자식 컴포넌트 관리뿐만아니라 본인이 가지고 있는 DOM Node도 관리해야합니다. 부모에게 너무 많은 역할을 맡긴것입니다.

 

state가 늘어날수록 코드는 제곱으로 늘어납니다. 그리고 부모가 자식을 직접적인 참조로 가지고 있기 때문에 부모와 자식이 아주 강하게 묶여 있다는 단점도 있었죠.

리액트는 이런 단점들을 어떻게 해결했을까?

리액트는 이런 현상을 Elements로 해결했습니다. 리액트에서 Elements란 쉽게말해 컴포넌트를 JSON으로 표현한것입니다.

Element는 instance가 아닙니다!

우리는 JSON형태의 Element를 리액트에게 전달해주면 리액트가 알아서 화면을 그려줍니다.

 

React는 아래와 같은 DOM을

<button class='button button-blue'>
  <b>
    OK!
  </b>
</button>

아래와 같은 React Element로 해석합니다.

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      children: 'OK!'
    }
  }
}

type이 string인 경우 type은 해당 컴포넌트가 어떤 HTML Tag인지를 표현합니다.

type이 string인 경우 props는 해당 HTML Tag의 속성들을 명시합니다.

 

만약에 아래와 같이 React Elementtype으로 string이 아닌 다른 ClassFunction이면 어떨까요?

{
  type: Button,
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

이게 바로 리액트의 핵심 아이디어입니다.

 

Button 엘리먼트를 약간 변형한 DangerButton이라는 엘리먼트가 있다고 해봅시다.

const DangerButton = ({ children }) => ({
  type: Button,
  props: {
    color: 'red',
    children: children
  }
});

 

DangerButtonButton이 div와 같은 Dom Node인지, Class인지 Function인지 전혀 신경 쓸 필요가 없습니다. 그냥 Button 엘리먼트에 color props만 다르게 넣어주고 있죠.

 

한마디로 React의 Element란 Dom Node(p, span, div...)나 리액트 컴포넌트(class or function)에 대한 JSON 요약본입니다.

 

아래와 같은 함수형 컴포넌트는

const DeleteAccount = () => (
  <div>
    <p>Are you sure?</p>
    <DangerButton>Yep</DangerButton>
    <Button color='blue'>Cancel</Button>
  </div>
);

이런 React Element로 변합니다.

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'
      }
   }]
});

이렇게 컴포넌트를 합치기 때문에 리액트에서 부모 자식 관계를 느슨하게 만들수 있었습니다.

 

리액트가 이런 엘리먼트를 만나면

{
  type: Button,
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

리액트는 Button Element가 어떤 Element인지 찾아서 아래와 같은 결과를 리턴합니다.

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      children: 'OK!'
    }
  }
}

typestring이 될때까지 계속 찾습니다. (DOM Node를 찾을때까지)

 

리액트 컴포넌트는 props라는 input을 받아서 element를 리턴하는 함수 혹은 클래스입니다.

 

컴포넌트로부터 리턴된 Element TreeDOM Node를 설명할 수도 있고 다른 컴포넌트를 설명하고 있을수도 있습니다.

이런 방식때문에 리액트가 다른 컴포넌트의 내부 구조를 몰라도 서로 독립적으로 합쳐질수 있는겁니다.

 

우리는 리액트에게 Element(설명서)를 전달하기만 했고 실제로 컴포넌트를 생성하고 제거하고 업데이트하는건 리액트가 알아서 해줍니다. 우리는 컴포넌트를 이렇게이렇게 만들어주세요라고 Element의 형태로 요청만 하는거죠.

 

class Button extends React.Component {
  render() {
    const { children, color } = this.props;

	// JSX로 표현된 컴포넌트는
    return <button><b>{children}</b></button>
  }
}

class Button extends React.Component {
  render() {
    const { children, color } = this.props;

	// 이렇게 JSON형태로 표현된 Element로 변환됩니다.
	return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
}

 

만약에 이런 함수를 호출 하면

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

리액트는 Form 컴포넌트가 어떤 Element Tree인지 궁금해합니다. 그걸 알때까지 집요하게 물어보죠.

// 리액트: Form이 뭐야?
{
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}
// React: Form에 있는 이 Button은 뭐야?
{
  type: Button,
  props: {
    children: 'OK!',
    color: 'blue'
  }
}
// React: Form에 있는 Button을 보니 Dom Node군! 이제 그만 물어봐도 될거같애
{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

이런식으로 Dom Node를 찾을때까지 집요하게 물어봅니다. 그래서 결국에 Form이라는 컴포넌트가 어떤 React Element Tree로 리턴되는지를 알게 되었죠.

 

리액트가 이렇게 Element를 구성하기 때문에 최적화 하기가 좋습니다. 중간에 props가 바뀌지 않은 컴포넌트가 있다면 그 컴포넌트 포함 모든 자식들을 리렌더링할 필요가 없습니다. 그 변하지 않은 컴포넌트 부터는 기존에 만들어놨던 컴포넌트를 그대로 다시 렌더링하면 되는거죠.

Instance는 위에서 설명한 Element와 Component에 비해 별로 중요하지 않습니다.

그냥 리액트의 클래스형 컴포넌트를 인스턴스화한걸 Instance라고 표현하는겁니다. 함수형 컴포넌트는 Instance가 없죠.

절대로 직접 Instance를 생성하지마세요 리액트가 알아서 해줍니다.

 

Element의 type란에 Class or Function을 명시해야지 Class의 Instance를 명시하면 리액트는 그걸 해석을 못합니다.

 

 

 

 

 

 

 

 

출처

medium.com/@dan_abramov/react-components-elements-and-instances-90800811f8ca

 

React Components, Elements, and Instances

Many people get confused by the difference between components, their instances, and elements in React. Why are there three different terms…

medium.com

 

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함