kunkunwoo@blog:~$ 거누권의 생각깜지

jsx, React.createElement, element

· 배운 것 · 12분 읽기

jsx란?

react component안을 보면 html tag처럼 생긴걸 볼수 있다.
jsx는 javascript의 확장 문법으로, ui가 어떻게 생겨야 하는지 간단히 작성할수있다.

//예시
import React from 'react';

const Test = () => {
  //return안에 있는 html tag같은게 jsx
  return (
    <div>
    </div>
  )
}

export default Test;

JSX는 React.createElement(component, props, ...children) 함수에 대한 문법적 설탕을 제공할 뿐입니다.

한문장으로 정의하자면 이렇다. ( JSX 이해하기 머릿글이다.)
jsx는 그냥 React.createElement(...args)을 우리가 보기 편한 형태인 html tag형태로 치환한 문법일 뿐이다.

그러면 이제 이 궁금증이 꼬리에 꼬리를 물고 생길것이다.

질문: 그럼 치환되는 형태인 React.createElement(...args)는 도대체 뭐냐?..
-> 함수의 이름으로도 유추할수있는데, react의 element를 return 한다.
질문: react의 element는 또 뭐냐?? ㅡㅡ

react의 element??
react의 element??

이 질문에 대한 답을 하기전에, 전통적인 UI programming과 react의 차이점에 대해서 보자.

리액트가!! (인스턴스 관리를 해줌)
리액트가!! (인스턴스 관리를 해줌)

전통적인 ui programming과 react의 가장 큰 차이점은

직접 DOM을 제어할 필요가 없다.

즉 전통적인 방식처럼 instant의 관리도 할 필요가 없는것이다. ex) instant 생성, 삭제, 업데이트 등등
그래도 이해가 안갈수 있으니, 이제 code level에서 살펴보자.

전통적인 ui programming 방식

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

위 코드에서 Form component(class)는
1. button과 message의 instance를 가지고 있다.
2. 각각의 instance의 create update delete에 대해서, 이 form component에서 다 관리해주고 있다.

이뿐만이 아니라, 이 코드는 서로 밀접하게 이어져있기 때문에, 추후에 분리나 다른 요소의 추가 같은 경우에 쉽지 않다.

react는 ??

우리가 작성한 element를 react에 전달하면, react가 이 element를 보고 알아서 관리를 해준다.

element: An element is a plain object describing a component instance or DOM node and its desired properties ( component instance나 dom node의 property들을 설명하는 object )
1. element는 react에게 우리가 화면에 뭘 그려야 할지 알려주는 객체!!
2. 우리가 instance에 직접 접근해서 method를 call 할수 없다. 그저, type과 props 두개의 field를 가진 객체다.
3. react가 이 element를 보고 instance를 제어한다.

쉽게 비유를 들자면, 우리가 react에게 ui rendering에 대해서 어떻게 해달라고 부탁하는 주문서라고 생각하면 더 쉽다.이제 우리는 jsx부터 element까지 알게 되었다.


여기서부터는 element에 대해서 더 자세히 알아보는 부분이므로, 넘어가도 좋다.

밑에 있는 링크글과 내용이 동일하니, 이 글을 읽어도 좋고..ㅎㅎ
https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html

React Components, Elements, and Instances – React Blog

element 형식

//이 type을 통해 react component를 뜻하는지, dom tag element를 뜻하는지 구분한다.
type: (string | ReactClass)
props: Object

//DOM element
{
  type: 'button', //string, html tag name 이다.
  props: {
    className: 'button button-blue',
    //children은 children prop을 이용해서 포함한다. 
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

//Component Element
{
  type: Button, //ReactClass 
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

element의 동작
이런 element가 있다고 하자

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

react는 type이 string이 아닐시 (html tag name이 아닐시)
type이 string이 될때까지 찾아간다. 여기서는 Button이 무엇인지

//Button의 return 값
{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

이제 맨위의 Form을 react의 방식대로 작성해보자.

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

instance의 생성, 삭제, 갱신들을 더이상 신경쓸 필요가 없으며, 코드 자체도 간략해진다.

조금의 노력으로 최적화가 가능하다.

밑의 코드를 실행시에

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

react는 밑의 과정처럼 점진적으로 정리를 해간다.

// 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!'
      }
    }
  }
}

이 과정이 reconciliation이다.

이건 ReactDOM.render() or setState()를 call할때 시작된다.
reconciliation이 끝나게 되면, renderer (react-dom or react-native)가 update의 필요성이 있는 dom node를 update한다.

이 과정 덕분에 react app이 최적화가 쉽다. 예를 들어 어떤 컴포넌트가 관련된 props가 변경되지 않은 경우 건너뛰는게 가능하다.
(Reconciliation: React에서 어떤 부분들이 변해야하는지 서로 다른 두 개의 트리를 비교하는 데 사용하는 알고리즘)

Reconciliation에 대해서 더 알고 싶다면

https://ko.reactjs.org/docs/reconciliation.html

재조정 (Reconciliation) – React

이 글을 한번 읽어보길 바란다. 어떠한 알고리즘을 썼고 어떠한 상황에서 빠른지에 대해서 적혀있다.


참고

https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html

React Components, Elements, and Instances – React Blog