React element 우리 친해질까 ..?

slobber·2025년 1월 28일
0
post-thumbnail

평소에 React로 개발하면서 JSX문법도 사용하고, 컴포넌트도 만들고... 근데 가끔 "이게 정확히 어떻게 동작하는 거지?" 하는 생각이 들더라고요.
이번 기회에 React의 핵심인 element에 대해 제대로 이해하고 한 단계 성장해보려고 합니다🥹


React 엘리먼트란?

React 엘리먼트는 React의 가장 기본적인 구성 단위예요.
쉽게 말하면 "화면에 그려질 내용을 담고 있는 자바스크립트 객체"라고 할 수 있죠. DOM 엘리먼트가 실제 화면의 요소라면, React 엘리먼트는 그것을 표현하는 설계도라고 생각하시면 됩니다


Element 타입별 처리 과정

React Element 의 type

React 엘리먼트의 type에는 크게 두 가지가 있어요

  • 문자열 타입

    'div', 'span' 같은 일반 HTML 태그를 나타내요

  • 함수/클래스 타입

    우리가 만든 컴포넌트를 나타내요
    최종적으로 HTML 엘리먼트로 변환될 때까지 처리됩니다


이게 무슨 이야기냐구요?
예를 들어볼게요. 우리가 보통 이렇게 코드를 작성하잖아요

// JSX로 작성한 코드
<div className='box'>
  <p>안녕!</p>
</div>

이게 실제로는 이런 객체로 변환된답니다

// 문자열 타입
{
  type: 'div',
  props: {
    className: 'box',
    children: {
      type: 'p',
      props: {
        children: '안녕!'
      }
    }
  }
}

신기하죠? 우리가 작성한 JSX가 이런 순수 자바스크립트 객체로 변환되는 거예요.

만약 type 에 우리가 작성한 컴포넌트가 위치한다면 어떻게 되는 걸까요 ?

// 먼저 이런 컴포넌트가 있다고 해볼게요
function Button(props) {
  return <p>{props.children}</p>;
}

// 이렇게 사용하면
<Button>안녕!</Button>

// React element 는 이런 모양이 됩니다
{
  type: Button,  // 여기서 type은 Button 함수 자체입니다!
  props: {
    children: '안녕!'
  }
}

// Button 컴포넌트가 실행되면 다음과 같은 엘리먼트가 반환됩니다
{
  type: 'p',  // 이제 type이 문자열입니다
  props: {
    children: '안녕!'
  }
}

여기까지 흐름을 봤다면 궁금증이 생기지 않나요 ?

{
  type: Button,  // 여기서 type은 Button 함수 자체입니다!
  props: {
    children: '안녕!'
  }
}

type 의 Button 컴포넌트가 어떻게

  props: {
    children: '안녕!'
  }

의 값을 받아서 사용할수 있을지 ? 궁금하잖아요 🥹🥹🥹

이해하기 쉽게 element 처리 과정을 작성해보자면

// 간단한 의사 코드로 보는 React의 처리 과정
function reconcileElement(element) {
  if (typeof element.type === 'string') {
    return createDOMElement(element);
  } 
  else if (typeof element.type === 'function') {
    const childElement = element.type(element.props);
    return reconcileElement(childElement);
  }
  else if (typeof element.type === 'class') {
    const childElement = element.type(element.props);
    return reconcileElement(childElement);
  }
}

짜잔 ! 다음같은 흐름으로 컴포넌트가 props 를 사용할수 있게 되는것이였어요!


⚙️ 실제 코드 살펴보기

이제 간략하게 알아봤으니 이번에는 딥~하게 알아볼까요~~

1. type 이 html 코드일 경우

{
  type: 'div',
  props: {
    className: 'box',
    children: {
      type: 'p',
      props: {
        children: '안녕!'
      }
    }
  }
}

react fiber node 를 생성하는 단계에서

 case HostComponent:
      return updateHostComponent(current, workInProgress, renderLanes);

다음 코드가 실행되게 됩니다!

HostComponent 코드는 내부적으로

if (props 에 children이 또 없다면) {
  nextChildren = null
} else if (아니 ?! 나는 또 children에 자식이 있는데 ?!) {
    // 다음 자식을 탐색하기위한 처리 
}

element 를 검사해요 

이게 무슨 이야기냐

- if 의 경우

{
  type: 'div',
  props: {
    className: 'box',
    children: '안녕!'
  }
}

- else if 의 경우
{
  type: 'div',
  props: {
    className: 'box',
    children: {
      type: 'p',
      props: {
        children: '안녕!'
      }
    }
  }
}

라는 이야기인거죠

그후에는 다시 fiber node 를 반환해줍니다 !

return workInProgress.child;


2. type 이 함수형 컴포넌트나 클래스 일시

case FunctionComponent: {
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps : 다른 로직

      return updateFunctionComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes,
      );
    }

형태가 되어 updateFunctionComponent 를 실행하게 되어요!

updateFunctionComponent 는 내부적으로

  nextChildren = renderWithHooks(
      current,
      workInProgress,
      Component,
      nextProps,
      context,
      renderLanes,
    );

다음 코드를 다시 실행합니다!

props 로 전달 되었던 Component 가 다시 전달되어 nextChildren 이 되는데 !

위의 코드를 봤다면 알겠지만

const Component = workInProgress.type; 입니다!!

그렇기때문에 제가 보여줬던 간략한 처리 과정 코드

 else if (typeof element.type === 'function') {
    const childElement = element.type(element.props);
    return reconcileElement(childElement);
  }

구조가 될수 있었던 거죠 🥹

마지막으로

만약에 우리가 작성한 코드가 그냥 문자열이라면 ?

const hi = () => {
  return '안녕!'
}

이라면 어떻게 처리 될까요 ?

    case HostText:
      return updateHostText(current, workInProgress);

다음 코드가 실행되고 updateHostText 은 내부적으로

function updateHostText(current: null | Fiber, workInProgress: Fiber) {
  return null;
}

단순 문자열이기때문에 null 처리가 되는걸 확인할수있네요!!


내용 요약

React Element 란?

  • React의 가장 기본적인 구성 단위
  • JSX로 작성한 코드가 변환되는 순수 자바스크립트 객체
  • DOM 엘리먼트의 설계도 역할

Element의 Type과 처리

  • React Element는 type에 따라 다르게 처리됩니다

  • 문자열 타입 ('div', 'span' 등)

    HTML 태그를 표현
    updateHostComponent를 통해 처리
    children 존재 여부에 따라 다른 로직 실행

  • 함수/클래스 타입 (우리가 만든 컴포넌트)

    해당 컴포넌트 함수 실행
    반환된 엘리먼트를 다시 처리
    최종적으로 HTML 엘리먼트가 될 때까지 반복

--

끝마치며...

간단하게 이해하기는 쉽지 않은 내용이라 내용이 길어졌네요 🤐
분명 제가 이해한 내용에 오류가 있을수도 있어요 !! 만약 저의 이야기에 틀린 내용이 있다면 주저마시고! 바로 잡아주시면 감사하겠습니다 🙇🏻‍♂️

정답지: https://github.com/facebook/react/tree/main

profile
안녕하세요 성장하는 개발자입니다.

0개의 댓글

관련 채용 정보