본문 바로가기
개발공부일지/React

React - 왜 React 가 대세가 되었을까?

by Hynn1429 2023. 8. 9.
반응형

안녕하세요.

Hynn 입니다.

 

이번 포스팅에서는 React 가 왜 필요하고, 대세가 되었는지 간략하게 정리해보도록 하겠습니다.

시작해보겠습니다.

 

1) Component 

 

React 가 왜 대세가 되었는지를 간략하게 살펴보도록 하겠습니다.

먼저 이를 이해하기 위해서는 HTML 의 몇가지 요소를 살펴보는게 좋습니다.

이를 위해서 간단한 코드를 하나 작성해보도록 하겠습니다.

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <header>
      <h1>Header</h1>
    </header>
    <nav>
      <ul>
        <li><a href="#">Menu 1</a></li>
        <li><a href="#">Menu 2</a></li>
        <li><a href="#">Menu 3</a></li>
      </ul>
    </nav>
    <article>
      <h2>Body</h2>
      <h3>Article</h3>
    </article>
    <footer><h4>Footer</h4></footer>
  </body>
</html>

간략하게 구현한 홈페이지의 레이아웃 예시입니다.

일반적으로 홈페이지는 Header 라고 하는 상단 이 고정되어 있고, Nav 라고 하는 메뉴 섹션,

실제로 컨텐츠가 담기는 Article/Body 와 같은 Section, 

그리고 마지막으로 사이트의 정보나 요약사항이 포함되는 Footer 형식으로 작동이 되어 있습니다.

 

이를 Tistory 홈페이지를 예시로 들면 아래와 같이 분류할 수 있습니다.

 

위의 예시를 본다면, 현재 위의 상단이 Header 가 되고, Header 내에 Nav 메뉴가 피드 스토리와 같이 구성이 되어 있습니다.

그리고 메인의 Artcle 영역을 크게 컨텐츠 영역으로 분류하고,

하단의 Footer 형태로 구성이 되어 있습니다.

 

이렇게 될 경우, HTML 로 일반적으로 구현한 페이지에서는, 홈페이지 이동시 바뀌는 컨텐츠 영역말고는 수정이 필요가 없습니다.

달리 말하면, Header 가 수정이 되어야 한다면, 모든 페이지가 수정되어야 합니다.

Footer 역시도 마찬가지입니다.

 

이렇게 되면 효율성에 문제가 발생합니다.

이를 바로 Shotgun Surgery (산탄총 수술) 이라고 합니다.

 

즉, 유지보수 측면에서 비효율성이 매우 크게 증가합니다. 

반면에 React 에서는 이를 이를 "Component" 화로 구현할 수 있습니다.

 

이를 어떤식으로 구성하는지를 예시를 살펴보도록 하겠습니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <MyHeader />
    <Navigation />
    <article>
      <h2>Body</h2>
      <h3>Article</h3>
    </article>
    <MyFooter />
  </body>
</html>

 

기존의 Header, Footer, Nav 와 같은 변하지 않는 Component 를 별도로 모듈화를 하는 것입니다.

이는 이후에 객체지향 프로그래밍(OOP) 에 대한 설명에서 보다 자세히 다루도록 하겠습니다.

이렇게 작성할 경우, 이미 모듈화가 이루어진, MyHeader, Navigation, MyFooter 만 수정하면, 모든 페이지에 별도의 수정 없이도 컨텐츠가 수정이 됩니다.

 

즉, 공통적으로 사용되는 요소들을 하나의 Component 로 구현함으로써, 코드의 재사용성을 증가시키고, 유지보수측면에서 기존의 방식에 비해 효율성이 증가합니다.

 

만약 문제가 발생하더라도, 문제가 발생하는 요소가 기존의 방식에서는 모든 파일을 다 수정해야 합니다.

즉, 100개의 페이지라면 100개 모두 copy&paste 를 하더라도, 100번의 작업이 필요하지만, Component 화가 된 구성에서는 문제의 Component 만 수정하면, 모든 페이지를 별도로 작업하지 않더라도 자동으로 수정이 완료됩니다.

 

즉, React 는 Component 기반의 UI Library 이기 때문에, 이러한 기술을 적극적으로 사용할 수 있습니다.

이것이 React 가 가진 가장 큰 장점중에 하나입니다.

 

2) 

 

두번째를 위한 간단한 예제입니다.

아래의 Counter 는 말 그대로, 버튼을 누르면 1씩 +, -가 되는 기본적인 Counter 입니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <script>
    const btnPlus = () => {
      const result = document.getElementById('result');
      result.innerHTML = parseInt(result.innerHTML) + 1;
    };
    const btnMiner = () => {
      const result = document.getElementById('result');
      result.innerHTML = parseInt(result.innerHTML) - 1;
    };
  </script>
  <body>
    <p>Counter</p>
    <h3 id="result">0</h3>
    <div>
      <button onClick="btnPlus()">+</button>
      <button onClick="btnMiner()">-</button>
    </div>
  </body>
</html>

위의 코드 예시를 살펴보면, Script 영역에 각 버튼의 대한 이벤트를 작성해두었습니다.

그리고, HTML Element 에서 결과를 표시할 Element 를 result 라는 이름으로 지정합니다.

그리고 나서, 각 버튼 이벤트 함수에, 이를 반영하기 위해 처리하는 로직을 구현했습니다.

 

이를 바로 명령형 프로그래밍이라고 합니다.

즉, 절차를 하나하나 나열함으로써, 구현하는 것입니다.

 

위의 코드를 명령형 프로그래밍의 방식으로 읽자면, 아래의 순서대로 절차를 나열할 수 있습니다.

 

  • 결과를 표시할 요소를 선택합니다. 여기서는 getElementByID 를 사용하여 result 라는 Element 를 선택합니다.
  • 그리고 나서, 현재의 결과값을 10진수 기준, 즉 숫자형으로 처리하기 위해 ParseInt 를 사용하여 +, - 처리를 수행합니다.
  • 버튼을 누르게되면 버튼에 맞게 + , - 가 1씩 숫자로 처리됩니다.

하지만 로직이 복잡하거나, 단계가 여러개일수록, 코드가 비효율적으로 길어집니다.

즉, 코드가 길어짐으로써, 가독성이나, 관리에 어려움을 겪게 됩니다. 이러한 명령형 프로그래밍 방식의 대표주자에 jQuery 가 존재합니다. 

물론 jQuery 내에서도 다른 방식을 지원하고 있기는 하지만, 많은 사용예시들이 이러한 단계를 따르고 있습니다.

 

(사실 저는 jQuery 는 사용해보지 않았습니다. 코드가 무겁다는 이야기가 많아서...)

 

반면에, React 에서는 "선언형 프로그래밍" 방식을 주로 사용합니다.

즉 선언형은 쉽게 설명하면 "난 이걸 할거에요" 라고 선언을 하고, 그에 대한 처리를 간결하게 코드로 구현하는 방식입니다.

위의 예제를 React 로 선언형으로 처리하면 아래와 같이 구현할 수 있습니다. 

 

물론, 명령형 프로그래밍이 상황에 따라 장점을 가질 수 있습니다.

하지만 최근 Web Development 의 대세가 선언형 프로그래밍이 더 많은 추세이기도하고, 더 간결하게 작성이 가능해서, 이를 따르는 구성이 많습니다.

 

React 의 예시를 사용하여 코드를 구성하면 아래와 같이 작성할 수 있습니다.

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      class Counter extends React.Component {
        constructor() {
          super();
          this.state = {
            count: 0
          };
        }

        btnPlus = () => {
          this.setState(prevState => ({
            count: prevState.count + 1
          }));
        };

        btnMiner = () => {
          this.setState(prevState => ({
            count: prevState.count - 1
          }));
        };

        render() {
          return (
            <div>
              <p>Counter</p>
              <h3>{this.state.count}</h3>
              <div>
                <button onClick={this.btnPlus}>+</button>
                <button onClick={this.btnMiner}>-</button>
              </div>
            </div>
          );
        }
      }

      ReactDOM.render(<Counter />, document.getElementById('root'));
    </script>
  </body>
</html>

 

코드가 얼핏 보면 원래의 간단한 JavaScript 예제보다 길어 보일 수 있습니다. 

그러나 이 길이는 React의 특성과 선언형 프로그래밍의 접근 방식을 반영한 결과입니다.

React를 사용하는 주요 이유 중 하나는 위에서 설명한 첫번째 장점으로 언급한 UI 구성 요소를 재사용 가능한 컴포넌트로 구성하는 것입니다. 

이러한 컴포넌트화는 규모가 커질수록 유지 보수와 코드 관리의 효율성을 크게 향상시킵니다.

Counter는 클래스 컴포넌트로 구현되었습니다. 

이 클래스 내에서 constructor는 초기 상태를 설정하며, 이 초기 상태에는 count라는 키와 값 0이 포함되어 있습니다. 

btnPlus와 btnMiner 메서드는 이 상태를 업데이트하는 데 사용됩니다.

render 메서드는 컴포넌트의 UI를 반환합니다. 이 메서드는 현재 상태에 따라 다시 호출될 수 있으므로, 여기서 UI는 선언적으로 현재 상태를 반영합니다.

마지막으로, ReactDOM.render 함수는 Counter 컴포넌트를 실제 DOM의 root 요소에 렌더링합니다.

이렇게 구성된 React 코드는 상태의 변화에 따라 UI가 어떻게 업데이트되어야 하는지를 명확하게 표현하고, 코드의 모듈성과 재사용성을 높이는 데 큰 장점이 있습니다.

 

3) Virtual DOM

 

Virtual DOM 을 이해하기 위해서는 DOM 을 이해해야 합니다. 

DOM은 웹 문서, 즉, HTML과 같은 요소의 구조화된 표현을 제공하는 인터페이스입니다. 즉, 이 웹 문서를 트리 구조로 표현하기 위한 모델입니다. 여기서 우리가 사용하는 일반적인 DOM 조작은 브라우저에서 HTML/XML 문서등을 읽고, 문서를 구조화된 트리형태의  DOM 으로 변환하는 역활을 수행합니다.즉, 여기서 변환된 DOM은 JavaScript 와 같은 스크립트 언어를 사용하여 동적으로 조작되거나 변경할 수 있습니다. 

 

하지만 React 는 여기서 VirtualDOM 이라고 하는 새로운 개념을 대중화시킨 라이브러리입니다.

일반적으로, DOM 조작은 웹 페이지의 상태(State), 그리고 데이터 (Data)가 변경될 때 마다, DOM을 직접 조작했어야 합니다.

즉, 데이터 변경이 발생하거나, 상태가 바뀔때마다 전체 DOM 트리를 다시 랜더링하는 것은 결과적으로 성능을 저하시킬 수 밖에 없게됩니다. 적은 부분이 수정되거나 변경될때마다 전체 DOM 트리를 다시 랜더링해야 하기 때문이죠.

 

반면에 React 에서 도입한 VirtualDOM 은 이를 효율적으로 처리하는 대중화된 라이브러리입니다.

React 의 장점으로 꼽히는 대표격인 VirtualDOM 은, 실제 DOM의 메모리 내 표현입니다. 즉, 단어 그대로 가상의 DOM 입니다. 

기존의 DOM 조작에서는 상태나, 데이터가 변경될 때, 실제 DOM 은 전체 DOM 트리를 랜더링하겠지만, React 에서는 VirtualDOM 을 업데이트 합니다.

 

그리고 나서, 업데이트 전의 VirtualDOM 과, 업데이트 이후의 DOM 을 비교하는 절차인 Reconciliation 과정을 거치게 됩니다.  단어의 뜻 자체가 회계에서 양쪽의 레코드가 일치하는지를 확인하는 절차를 의미합니다. 이렇게 되면, 전체 상태, 데이터가 변경된 부분만을 확인합니다. 즉, 변경된 부분만을 확인하여, 어떤 부분의 변경사항이 있는지, 조정해야하는지를 결정합니다.

 

그리고 나서, 위의 과정에서 결정된 변경사항을 실제 DOM에 반영합니다. 이를 우리가 Github 에서 흔히 말하는 "Commit" 이라는 단계를 거치게 됩니다.

이렇게 하면, 상태나, 데이터 변경이 빈번하게 발생하는 규모가 큰 서비스일수록 DOM의 효율이 크게 증가합니다. 

결과적으로 이 VirtualDOM 기술로 인해 React 는 UI의 상태관리&랜더링 뿐 아니라, 성능 최적화에 대한 새로운 패러다임을 제시한 라이브러리라고 할 수 있습니다.

 

 

위의 세가지의 장점은 글로써 100% 표현이 된다고 할 수는 없지만, 핵심 개념은 이해해야 할 것으로 생각됩니다.

 

감사합니다. 

반응형

댓글