React 시작 및 사용해보기

React 워밍업

React 시작하기

React는 사용자 인터페이스를 만들기 위한 자바스크립트 라이브러리로, 점진적으로 적용할 수 있도록 설계되어있어 필요한 만큼만 적용할 수 있는데, 대표적인 특징은 다음과 같습니다.

선언형
React는 상호작용이 많은 UI를 만들 때 생기는 어려움을 줄여준다. React는 데이터가 변경됨에 따라 적절한 컴포넌트만 효율적으로 갱신하고 렌더링하는데, React의 선언형 뷰는 코드를 예측 가능하고 디버그하기 쉽게 만들어 준다.
컴포넌트 기반
React의 컴포넌트 로직은 템플릿이 아닌 자바스크립트로 작성되는데, 따라서 다양한 형식의 데이터를 앱 안에서 손쉽게 전달할 수 있고, DOM과는 별개로 상태를 관리할 수 있다.
폭 넓은 확장성
React는 기술 스택의 나머지 부분에 대해서는 관여하지 않기 때문에, 기존의 코드를 다시 작성하지 않고도 React의 새로운 기능을 이용해 개발할 수 있고, Node 서버에서 렌더링을 하거나 React Native를 이용하여 모바일 앱을 만들 수도 있다.

React 샘플 코드

React는 자바스크립트 라이브러리인 만큼 HTML 페이지에 쉽게 적용해서 사용할 수 있는데, 간단한 테스트를 위해서는 Code Pen, Code Sandbox와 같은 온라인 편집기에서는 물론이고, 다음과 같이 간단한 HTML 코드를 구성해서 브라우저의 로컬 파일 시스템에서 열어 볼 수도 있습니다. 하지만 홈페이지에 따르면 런타임 코드 변환이 느리기 때문에 간단한 데모에만 다음의 코드를 사용하는 것이 좋다고 합니다.

React 샘플 코드
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">

      function MyApp() {
        return <h1>Hello, world!</h1>;
      }

      const container = document.getElementById('root');
      const root = ReactDOM.createRoot(container);
      root.render(<MyApp />);
    </script>
  </body>
</html>

React 사용해보기

컴포넌트 추가

React를 사용해보는 가장 쉬운 방법은 기존의 페이지에 스크립트를 적용해보는 겁니다. 만약 편집할 기존의 웹사이트 페이지가 없다면 새 HTML 파일을 만들어 사용해 볼 수도 있습니다.

우선 편집할 HTML 파일을 열고 like_button라는 클래스의 div 태그를 추가해야 하는데, 이 태그를 통해 React의 컴포넌트가 표시되도록 만들기 위해서입니다.

OM 컨테이너 추가하기
index.html
<div class="like_button"></div>

다음으로 React를 사용할 수 있도록 다음과 같이 React 라이브러리를 추가해 줍니다.

React 라이브러리 추가하기
index.html
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>

이제 React를 본격적으로 사용하기 위해 React를 사용할 수 있는 스타터 코드를 작성해 줘야 하는데, 스타터 코드와 함께 앞에서 추가했던 DOM 컨테이너에 버튼을 추가해주는 렌더링 코드도 작성해 주어야 정상적으로 표시가 됩니다.

React 스타터 코드
index.html
'use strict'

const e = React.createElement;

class LikeButton extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            liked: false
        }
    }

    render() {
        if (this.state.liked) {
            return '좋아요를 눌렀습니다.';
        }

        return e(
            'button', {
                onClick: () => this.setState({
                    liked: true
                })
            },
            '좋아요'
        )
    }
}
React 렌더링 코드
index.html
const buttonContainer = document.querySelector('.like_button');
const root = ReactDOM.createRoot(buttonContainer);
root.render(e(LikeButton));

테스트를 위한 예제 파일의 전체 코드는 다음과 같습니다.

예제 전체 코드
index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>버튼 테스트</title>
</head>
<body>

    <div class="like_button"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script>
        'use strict'

        const e = React.createElement;

        class LikeButton extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    liked: false
                }
            }

            render() {
                if (this.state.liked) {
                    return '좋아요를 눌렀습니다.';
                }

                return e(
                    'button', {
                        onClick: () => this.setState({
                            liked: true
                        })
                    },
                    '좋아요'
                )
            }
        }

        const buttonContainer = document.querySelector('.like_button');
        const root = ReactDOM.createRoot(buttonContainer);
        root.render(e(LikeButton));
    </script>

</body>
</html>

컴포넌트 재사용

일반적으로 컴포넌트는 하나의 웹페이지에서 여러번 재사용하는 경우가 많습니다. 컴포넌트를 재사용하는 방법은 다음과 같이 추가할 컴포넌트를 위한 DOM을 추가로 생성하고, 해당 DOM을 순환하는 렌더링 코드를 작성해주면 됩니다.

컴포넌트 재사용을 위한 DOM 콘테이너 추가
index.html
<div class="like_button" data-componentid="1"></div>
<div class="like_button" data-componentid="2"></div>
<div class="like_button" data-componentid="3"></div>
<div class="like_button" data-componentid="4"></div>
<div class="like_button" data-componentid="5"></div>
컴포넌트 재사용을 위한 순환 렌더링 코드
index.html
document.querySelectorAll('.like_button').forEach(buttonContainer => {
    const componentId = parseInt(buttonContainer.dataset.componentid, 10);
    const root = ReactDOM.createRoot(buttonContainer);
    root.render(e(LikeButton, {
        componentId: componentId
    }));
});

컴포넌트 재사용 예제의 전체 코드는 다음과 같습니다.

컴포넌트 재사용 예제 전체 코드
index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>버튼 테스트</title>
</head>

<body>

    <div class="like_button" data-componentid="1"></div>
    <div class="like_button" data-componentid="2"></div>
    <div class="like_button" data-componentid="3"></div>
    <div class="like_button" data-componentid="4"></div>
    <div class="like_button" data-componentid="5"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script>
    'use strict'

    const e = React.createElement;

    class LikeButton extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                liked: false
            }
        }

        render() {
            if (this.state.liked) {
                return this.props.componentId + ' 좋아요를 눌렀습니다.';
            }

            return e(
                'button', {
                    onClick: () => this.setState({
                        liked: true
                    })
                },
                '좋아요'
            )
        }
    }

    document.querySelectorAll('.like_button').forEach(buttonContainer => {
        const componentId = parseInt(buttonContainer.dataset.componentid, 10);
        const root = ReactDOM.createRoot(buttonContainer);
        root.render(e(LikeButton, {
            componentId: componentId
        }));
    });
    </script>

</body>

</html>

JSX 사용하기

앞에서 테스트한 코드에서는 브라우저가 기본적으로 지원하는 요소들만을 사용했기 때문에 자바스크립트의 함수들을 사용해 조금 복잡해 보였지만, React의 JSX를 사용하면 다음과 같이 조금 더 편리하게 사용할 수 있습니다.

React의 JSX 문법
return (
    <button onClick={() => this.setState({ liked: true })}>
        Like
    </button>
);

정적인 페이지에서 JSX 기능을 사용하기 위해서는 다음과 같이 babel 스크립트를 추가해주어야 하는데, 이 방식은 사이트를 느리게 만들기 때문에 추천되는 방법은 아닙니다.

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
JSX 문법을 사용한 Hello, World 예제
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>JSX 테스트</title>
</head>
<body>

    <div id="root"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <script type="text/babel">
    function MyApp() {
        return <h1>Hello, world!</h1>;
    }

    const container = document.getElementById('root');
    const root = ReactDOM.createRoot(container);
    root.render(<MyApp />);
    </script>

</body>
</html>
Node.js에서 JSX 실행하기

Node.js를 사용하면 프로젝트에 쉽게 JSX 전처리기를 추가할 수 있는데, 우선 터미널에서 임의의 프로젝트 폴더로 이동 한 후 다음의 두 명령어를 순서대로 입력해 보세요.

npm init -y

위 명령어를 실행하면 package.json 파일이 생성되는데, 정상적으로 명령이 수행되었다면 다음 명령어를 추가로 입력해 JSX 전처리를 위한 모듈을 설치해야 합니다. 모듈을 설치하고 나면 앞에서 생성된 package.json 파일의 dependencies라는 항목에 관련 모듈이 추가된 것을 확인할 수 있습니다.

npm install babel-cli@6 babel-preset-react-app@3
package.json
"dependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-react-app": "^3.1.2"
}

JSX 전처리기를 테스트하기 위해 src 폴더를 만들고 다음의 명령어로 Babel 컴파일러를 실행시켜 보세요.

JSX 전처리기 실행하기
npx babel --watch src --out-dir . --presets react-app/prod

참고로 npxnpm 5.2 버전 이상에 내장된 패키지 실행 도구로, 위 명령어를 실행하면 Babel 컴파일러는 자동으로 src 폴더의 스크립트의 변경 사항과 JSX를 감시하고, 최종 스크립트 파일을 자동으로 생성할 수 있습니다.

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>JSX 테스트</title>
</head>
<body>
    <div id="root"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="like_button.js"></script>
</body>
</html>
/src/like_button.js
'use strict';

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  render() {
    if (this.state.liked) {
      return 'You liked this.';
    }

    return (
      <button onClick={() => this.setState({ liked: true }) }>
        Like
      </button>
    );
  }
}

let domContainer = document.querySelector('#root');
ReactDOM.render(<LikeButton />, domContainer);

Babel구형 브라우저와의 호환성 문제를 걱정할 필요 없이 클래스와 같은 모던 JavaScript 문법을 쓸 수 있게 해주는 도구입니다.

src 폴더의 like_button.js 파일을 수정하면 루트 폴더에 like_button.js라는 이름의 모든 브라우저와 호환이 되는 순수 자바스크립트 파일을 생성해 주는 것을 확인할 수 있는데, Babel을 사용하게 되면 호환성 문제를 고려할 필요없이 최신 자바스크립트 문법을 쓸 수 있기 때문에 생산성 높은 코딩 작업을 할 수 있습니다.

변환 된 like_button.js 소스 코드
like_button.js
'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var LikeButton = function (_React$Component) {
  _inherits(LikeButton, _React$Component);

  function LikeButton(props) {
    _classCallCheck(this, LikeButton);

    var _this = _possibleConstructorReturn(this, (LikeButton.__proto__ || Object.getPrototypeOf(LikeButton)).call(this, props));

    _this.state = { liked: false };
    return _this;
  }

  _createClass(LikeButton, [{
    key: 'render',
    value: function render() {
      var _this2 = this;

      if (this.state.liked) {
        return 'You liked this.';
      }

      return React.createElement(
        'button',
        { onClick: function onClick() {
            return _this2.setState({ liked: true });
          } },
        'Like'
      );
    }
  }]);

  return LikeButton;
}(React.Component);

var domContainer = document.querySelector('#root');
ReactDOM.render(React.createElement(LikeButton, null), domContainer);

자바스크립트 툴체인

이미 만들어진 기존의 프로젝트에서 간단한 HTML 페이지에 React를 적용하는 경우라면 스크립트 태그를 사용하는 것이 가장 최선의 방법입니다.

하지만 새로운 앱 제작을 위해 프로젝트를 시작하는 경우라면 보다 통합된 설정을 할 수 있는 툴체인을 고려할 필요가 있습니다. 대규모의 애플리케이션을 제작하는 경우라면 권장되는 여러 자바스크립트 툴체인들 중에 하나를 사용하는 것이 훨씬 더 유리하기 때문이죠.

  • 많은 파일과 컴포넌트 스케일링이 필요한 경우
  • 서드 파티 npm 라이브러리를 사용하는 경우
  • 일반적인 실수를 조기에 발견해야 하는 경우
  • CSS와 JS를 실시간으로 편집해야 하는 경우
  • 프로덕션 코드를 최적화시킬 필요가 있는 경우

React 팀에서 추천하는 대표적인 자바스크립트 툴체인은 다음과 같습니다.

Create React App
React를 배우고 있거나 아니면 새로운 싱글 페이지 앱을 만들고 싶은 경우
Next.js
서버 렌더링 Node.js 웹사이트를 만드는 경우
Gatsby
고정적인 콘텐츠 지향적 웹사이트를 만드는 경우
Neutrino
webpack의 장점과 React의 단순함과 미리 설정된 앱과 컴포넌트를 합친 툴체인
Nx
풀스택 모노레포 개발을 위한 도구로, React, Next.js, Express 등을 기본적으로 지원함
Parcel
React와 함께 사용할 수 있고 빠르고 설정이 필요 없는 웹 애플리케이션 bundler
Razzle
서버 렌더링 프레임워크로 설정이 필요 없지만, Next.js보다 다루기 쉬운 장점이 있음

Create React App

Create React App은 쉽고 간편하게 React 싱글 페이지 애플리케이션을 생성해주는 패키지인데, 처음 React를 시작하는 경우에도 학습을 위해 간편하게 설치할 수 있습니다.

Create React App은 개발 환경을 설정하고, 최신 JavaScript와 프로덕션 앱 최적화를 지원해 주는데, Node.js14 버전 이상, NPM5.6 버전 이상이 필요합니다.

React 프로젝트는 다음과 같이 npx create-react-app {프로젝트}의 명령어로 생성할 수 있습니다.

npx create-react-app my-react-app
cd my-react-app
npm start

Create React App은 백엔드 로직이나 데이터베이스를 제어할 수는 없고, 프론트엔드의 빌드 파이프라인만 생성하기 때문에, 백엔드를 원하는 대로 사용할 수 있습니다. 또 Babel이나 webpack같은 build 도구를 사용하지만, 설정 없이도 동작할 수 있고, 프로덕션을 배포할 준비가 되었을 때, npm run build 를 실행하면 build 폴더 안에 제작한 앱의 최적화된 Build를 생성할 수 있습니다.

생성된 프로젝트에서 서버를 실행하고 http://localhost:3000로 접속하면 다음과 같은 화면을 볼 수 있습니다.

create react app 실행화면

Next.js

Next.js는 경량의 프레임워크로 React로 만들어진 스태틱 서버 렌더링 애플리케이션입니다. 기본적으로 스타일링과 라우팅 해결책을 가지고 있는데, Next.js를 사용하기 위해서는 Node.js를 서버 환경으로 사용하고 있어야 합니다.

Gatsby

Gatsby는 정적 웹사이트를 React로 만드는 경우에 가장 좋은 방법이 될 수 있습니다. Gatsby는 React 컴포넌트를 사용하게 해주지만 미리 렌더링 된 HTML과 CSS를 사용하기 때문에 빠르게 로드할 수 있습니다.

React CDN

React와 ReactDOM 모두 CDN을 제공하고 있는데, 개발용으로 적합한 버전과 용량 및 성능이 최적화된 배포용 버전이 있습니다.

개발용 버전
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
배포용 버전
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

답글 남기기