React.js - JSX란?(정의, 장점, 문법, 특징 등)

Gyu·2022년 1월 19일
2

React.js

목록 보기
2/20
post-thumbnail

이 시리즈는 리액트 공식문서 및 '리액트를 다루는 기술(김민준 저)', '리액트 교과서(아자트 마르단 저)'를 바탕으로 작성되었습니다. 개인 노션에만 정리한 내용을 옮기다 보니 저도 모르게 출처 없는 타 블로그 등의 글이 있을 수 있습니다. 혹 출처를 아시는 분들은 알려주시면 감사하겠습니다.

JSX란?

const element = <h1>Hello, world!</h1>;
  • 위에 태그 문법은 문자열도, HTML도아닌 JSX(JavaScript XML)라는 JavaScript에 XML을 추가하여 확장한 문법이다.
  • JSX는 React “엘리먼트(element)” 를 생성한다. React 엘리먼트는 브라우저 DOM 엘리먼트와 달리 일반 객체이다.
  • React는 JSX 사용이 필수가 아니지만, JS 코드 안에서 UI관련 작업을 할 수 있기 때문에 시각적으로 더 도움이 된다. 또한 JSX를 사용하면 React가 더욱 도움이 되는 에러 및 경고 메시지를 표시할 수 있게 해준다.

JSX 사용하기

  • 어떤 프레임워크를 사용해 웹앱을 만들든 가장 중요한 것은 최종결과가 HTML, CSS, JS의 조합이어야 한다는 것이다. (그렇지 않으면 브라우저가 이해하지 못하기 때문)
  • 리액트로 개발을 할 때 HTML, CSS, JS 코드를 작성하기도 하지만 상당부분을 JSX로 코드를 작성해야한다. 하지만 JSX는 공식적인 JS문법이 아니기 때문에 브라우저는 JSX를 이해하지 못한다. 때문에 리액트로 개발을 할 때는 JSX를 브라우저가 이해할 수 있는 평범한 자바스크립트로 변환시킬 방법이 필요하다.
  1. Node.js와 그 외 빌드 툴 등으로 구성된 개발환경을 구축하여 리액트로 개발하는 것
    • 빌드 툴을 이용해 JSX로 작성된 코드들이 JS로 변환되며, 다른 일반적인 JS 파일처럼 참조할 수 있도록 변환된 파일이 디스크에 저장된다.
    • 장점 : 오늘날 현대적인 웹개발에서 대표적인 방식, JSX에서 JS로 트랜스 파일됨, 여러 모듈과 빌드 툴 그리고 그 외 복잡한 웹앱의 관리에 필요한 많은 기능 이용 가능
    • 단점 : 처음에는 약간 복잡하고 시간이 걸림
  2. 런타임 시 브라우저가 JSX를 JS로 자동 변환 하게 해주는 방법
    • CDN을 이용하는 방식으로, 일반 JS처럼 JSX를 직접 지정하면 브라우저가 알아서 처리한다. 브라우저가 실행 될 때 CDN으로 연결한 스크립트 파일 하나만 참조하고, 그 스크립트 파일은 페이지가 로딩 될 때 JSX를 JS로 변환한다.
    • 장점 : 개발 환경 세팅 시간을 절약하고 코드 작성에 더 많이 집중 가능
    • 단점 : 브라우저가 매번 JSX를 JS로 변환해야 하는데, 이로 인해 소요되는 시간이 길어지면 브라우저 성능 저하를 야기 할 수 있다. 성능 이슈가 있으므로 실제 웹 개발에서는 사용하지 않음. 공부용에서만 추천!
    • <!-- 스크립트 태그 추가 - CDN -->
      <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>
      
      <!-- JSX를 JS로 변환시켜주는 바벨 추가 -->
      <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
      
      <!-- body 태그 닫히기 전에 리액트 코드 작성 -->
      <!-- 바벨이 트랜스파일링 할 수 있도록 type 속성 지정 -->
      <script type="text/babel">
      	// React 코드 작성
      </script>
      

JSX 변환 과정

  • JSX는 브라우저에서 실행되기 전에 코드가 번들링되는 과정에서 바벨을 사용하여 자바스크립트 형태로 변환된다.
    // JSX
    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    
    // JS로 변환된 JSX
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
  • JSX를 사용하지 않고 React.createElement() 함수를 사용하면 컴포넌트를 렌더링 할 수 있다. 하지만 이 방식은 JSX를 사용하는 방식보다 불편하다. JSX를 사용하면 쉽고 편하게 UI를 렌더링 할 수 있다.

ReactDOM.render(element, container[, callback])

  • 개발자가 작성한 JSX를 화면에 렌더링 하기 위해서는 ReactDOM.render() 함수를 사용해야한다. 이 함수는 컴포넌트를 페이지에 렌더링하는 역할을 하며, react-dom 모듈을 불러와 사용할 수 있다.
  • element : JSX로 작성한 화면에 출력할 내용
  • container : 첫 번째 인자인 JSX를 랜더링 해서 보여줄 DOM 안의 위치
  • ReactDom.render(
    	<h1>Hello World</h1>,
    	document.body
    );
  • 위 함수를 이용하면 최종결과가 HTML, CSS, JS로 만들어지고, 이를 브라우저가 이해할 수 있어 원하는 결과물이 출력된다.

JSX 장점

  1. 보기 쉽고 익숙하다.
    • JSX는 HTML 코드와 비슷하기 때문에 일반 자바스크립만 사용한 코드보다 더 익숙하며 가독성이 좋다.
  2. 높은 활용도
    • JSX에는 div, span 같은 HTML 태그를 사용할 수 있으며, 개발자가 만든 컴포넌트도 JSX 안에서 작성할 수 있다.

JSX 문법

반드시 태그는 닫혀야 한다.

  • <div>, <p>, <span>, <a> 같이 짝이 있는 태그의 경우 반드시 닫는 태그가 존재해야 한다. 그렇지 않을 경우 에러가 발생한다.
  • <img/>, <input/>, <br/> 같은 단독 태그(self-closing tag)의 경우에는 반드시 태그를 닫아줘야 한다. 그렇지 않을 경우 에러가 발생한다.

렌더링 될 루트 엘리먼트는 하나만 존재 해야 한다.

ReactDOM.render(
	<div>
		Hello
	</div>
	<div>
		Bye
	</div>,
	document.getElementById('root')
);
  • 위 예제처럼 렌더링 될 리액트 엘리먼트에서 루트 엘리먼트가 두 개 이상일 경우 에러가 발생한다. 때문에 두 개 이상의 루트 엘리먼트가 존재할 경우 아래와 같이 반드시 하나의 엘리먼트로 감싸져야 한다. (JSX는 자식 엘리먼트를 가질 수 있다.)
  • Virtual DOM에서 컴포넌트 변화를 감지해 낼 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다는 규칙 때문에, 리액트에서는 반드시 컴포넌트에 여러 요소가 있다면 반드시 부모 요소로 감싸야 한다.
ReactDOM.render(
	<div>
		<div>
			Hello
		</div>
		<div>
			Bye
		</div>
	</div>,
	document.getElementById('root')
);
  • 이처럼 하나의 엘리먼트로 감싸져야 하는 경우 무분멸한 div 태그를 사용하게 되고, 스타일 관련 코드가 꼬일 수도 있다. 이를 위해 리액트에서는 복수의 엘리먼트를 리턴하는 방법을 제공한다.

복수 엘리먼트 리턴

  1. 배열 문법 사용

    ReactDOM.render(
    	[ // 리액트 엘리먼트 배열을 반환
    		<div key="1">Hello</div>, // 복수의 아이템을 리턴할 경우  
    		<div key="2">Bye</div>    // 각 엘리먼트에 key 속성과 고유값을 지정해야 한다.
    	],
    	document.getElementById('root')
    );
  2. 리액트 v16.2.0 부터 추가된 프래그먼트(Fragment) 패턴 사용

    ReactDOM.render(
    	<React.Fragment> // React.Fragment 컴포넌트로 리액트 엘리먼트를 감싸준다.
    		<div>Hello</div>
    		<div>Bye</div>   
    	</React.Fragment>
    	document.getElementById('root')
    );
    
    // 프래그먼트 축약 구문 사용
    ReactDOM.render(
    	<>  // 빈태그로 감싸주기
    		<div>Hello</div>
    		<div>Bye</div>   
    	</>
    	document.getElementById('root')
    );
    • React.Fragment 컴포넌트는 실제로 DOM엘리먼트로 생성되지 않는다. 단지 HTML로 트랜스파일될 때 존재하지 않는 것으로 취급하라고 JSX에게 알려준다.
    • 각 엘리먼트들이 배열에 담겨져 있는 것이 아니므로 쉼표나 구분자가 필요 없다.
    • key속성과 고윳값을 지정할 필요가 없다.

JS 표현식 사용하기

  • JSX에서는 중괄호 { } 를 사용하여 JS 표현식을 쓸 수 있다.
    const name = 'Josh Perez';
    const element = <h1>Hello, {name}</h1>; // Hello, Josh Perez
    
    ReactDOM.render(
      element,
      document.getElementById('root')
    );
    
    //---------------------------------------------------------------------------
    
    ReactDOM.render(
      <p>Random number : {Math.random() * 100}</p>,
      document.getElementById('root')
    );
    // 중괄호는 표현식 먼저 평가 돼 그 결과를 리턴하게 만든다.
    
    //---------------------------------------------------------------------------
    
    // 주석 사용하기
    // JSX에서 주석은 {}로 감싸준다. 여러 줄 주석만 사용 가능하다.
    ReactDOM.render(
        <div>
            <p>Hello</p>
            {/* 주석은 이렇게 작성합니다. */}
            <p
    		className='react' // 시작 태그를 여러줄로 작성 시 주석 작성 가능
            >World</p>
        	// 하지만 이런 주석이나
        	/* 이런 주석은 페이지에 그대로 노출됩니다.*/
        </div>,
        document.getElementById('app')
    );

조건부 렌더링

삼항 연산자(조건부 연산자)를 사용한 조건부 렌더링

  • JSX 내부의 JS 표현식에서는 if문을 사용할 수 없다. 때문에 조건에 따라 다른 내용을 렌더링 하고자 할 경우 JSX 밖에서 if 문을 사용하거나, 중괄호 안에서 삼항 연산자를 사용하면 된다.
    class App extends Component {
        render() {
            let name = 'React';
            return (
                <div>
                    {
                        name === 'React' ? (
                            <h1>This is React.</h1>
                        ) : (
                            <h1>This is not React.</h1>
                        )
                    }
                </div>
            );
        } 
    }

AND 연산자(&&)를 사용한 조건부 렌더링

  • 특정 조건을 만족할 때만 내용을 보여주고 싶을 때 사용
    class App extends Component {
        render() {
            let name = 'React';
            return (
                <div>
                    {
                        name === 'React' && <h1>This is React.</h1>
                    }
                </div>
            );
        } 
    }

OR 연산자(||)를 사용한 조건부 렌더링

  • 리액트 컴포넌트에서는 함수에서 undefined나 null을 반환하면 렌더링을 하려하면 오류가 발생한다. 반면 JSX 내부에서 undefined나 null을 렌더링하는 것은 괜찮다.
  • JSX 내부에서 undefined나 null을 렌더링하면 아무것도 보여주지 않는다.
  • OR 연산자는 AND 연산자와 다르게 특정 값이 undefined나 null일 경우 보여주고 싶은 문구가 있을 때 주로 사용한다.
    class App extends Component {
        render() {
            let name = undefined;
            return (
                <div>
                    {
                        name === 'React' || <h1>This is React.</h1>
                    }
                </div>
            );
        } 
    }

JSX에서 속성 정의하기

  • HTML 엘리먼트에 속성을 정의할 수 있는 것처럼, JSX에서도 엘리먼트에 속성을 정의 할 수 있다. 하지만 JSX는 HTML보다는 JavaScript에 가깝기 때문에 JSX에서는 HTML 엘리먼트에 속성을 정의하는 방식과는 약간 다른 방식으로 속성을 정의 한다.
  • JXS가 반환하는 React DOM 엘리먼트에서는 기존 HTML 속성이 아닌 camelCase로 작성된 속성명을 사용해야 한다. 예를 들어, JSX에서 class는 className이 되고 tabindex는 tabIndex가 된다.
    • className이 아닌 class 값을 설정 시 스타일이 설정은 되지만 경고 문구가 뜬다. 하지만 v16 이상 부터는 class를 className으로 변환시켜주고 경고를 띄워준다.
  • JSX에서 속성값을 정의 할 때 중괄호 { }를 사용하여 JS 표현식을 사용할 수 있는데 이 경우 따옴표를 사용하지 않는다.
    // JSX에서 프로퍼티 명은 카멜케이스로 작성되어야 한다.
    const element = <div tabIndex="0"></div>; 
    
    // 속성값 정의 시 JS 표현식을 사용고자자 할 경우 따옴표를 사용하지 않는다.
    const element = <img src={user.avatarUrl}/>;
  • 속성값 정의 방법
    1. 따옴표를 사용하여 문자열 입력 → 정적
    2. 중괄호를 사용하여 JS표현식 사용. 이 경우에는 따옴표를 사용하지 않음 → 동적
    • 속성값을 정의 할 경우 위 두 가지 방법 중 하나만 사용해야 하며, 동일한 속성에 위 두가지 방법을 사용할 수 없다. 한 속성에 하나의 방식만 사용해야 한다.

인라인 스타일링

  • JSX에서는 style 속성 안에 직접 CSS를 포함할 수 없으며, 스타일 정보를 담은 객체를 참조해야한다. 스타일 객체의 경우 기존 CSS 속성 명을 camelCase로 작성한다.
    var element = <div style="color:red;">Hello World</div>; // 인라인 CSS 사용불가
    
    //--------------------------------------------------------------------
    
    // JXS에서 CSS를 적용하기 위해서는 스타일 객체를 만들어야 한다.
    var styleObject = {
    	color: "#333",
    	padding: 0,
    	backgroundColor: "black", // 스타일 각체의 속성은 모두 camelCase로 작성한다.
    	fontSize: "32" 
    }
    
    var element = <div style={styleObject}>Hello World</div>;
    
    //--------------------------------------------------------------------
    
    // 스타일 객체를 style 속성 내부에 선언 가능
    var element = 
    <div style={ { color: "#333", fontSize: "32" } }>
    	Hello World
    </div>;

JSX 특징

대소문자를 구별한다.

  • JSX에서 HTML엘리먼트를 작성할 때는 반드시 소문자를 사용해야 하지만, 컴포넌트를 작성할 때는 컴포넌트 클래스 이름과 동일하게 PascalCase로 작성되어야 한다.
    ReactDOM.render(
    	<div>
    		<MyCustomComponent/>
    	</div>,
    	document.getElementById('root')
    );

주입공격을 방지한다.

  • 기본적으로 React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프 처리하므로, 애플리케이션에서 명시적으로 작성되지 않은 내용은 주입되지 않는다. 모든 항목은 렌더링 되기 전에 문자열로 변환된다. 이런 특성으로 인해 XSS (cross-site-scripting) 공격을 방지할 수 있다.

객체를 표현한다.

  • Babel은 JSX를 React.createElement() 호출로 트랜스파일한다. 때문에 첫 번째 코드는 두 번째 코드로 트랜스 파일 된다.

    // 개발자가 작성한 코드
    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    
    // babel로트랜스 파일된 코드
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
  • React.createElement()는 버그가 없는 코드를 작성하는 데 도움이 되도록 몇 가지 검사를 수행 후, 기본적으로 다음과 같은 객체를 생성한다.

    const element = {
      type: 'h1',
      props: {
        className: 'greeting',
        children: 'Hello, world!'
      }
    }
  • 이렇게 생성된 객체를 “React 엘리먼트”라고 하며, 이는 화면에 표시하려는 항목에 대한 설명이라고 할 수 있다. React는 이러한 객체를 읽고 DOM을 구성하고 최신으로 유지하는 데 이러한 객체를 사용한다.

profile
애기 프론트 엔드 개발자

0개의 댓글