본문 바로가기
React

[리액트] JSX란? (정의, 역할, 장점 및 사용법)

by 그리득 2024. 5. 7.
728x90

토이 프로젝트를 하기 전 따로 공부하기 위해 작성한 글입니다.

jsx는 리액트로 개발할 때 필수적으로 사용해야한다.

JSX란?

JavaScript를 JS라고 많이한다.

A syntax extension to JavaScript 자바스크립트의 확장 문법이란 의미

자바스크립트의 문법을 확장했다는 뜻 (JavaScript + XML / HTML)

 

const element = <h1>Hello, world!</h1>;

JSX코드

 

JSX의 역할

내부적으로 XML, HTML 코드를 JavaScript로 변환하는 과정을 거치게된다.

그렇기 때문에 실제로 우리가 JSX로 코드를 작성해도 JavaScript코드로 나오게 된다.

여기서 JSX 코드를 JavaScript코드로 변환하는 역할을 하는 것이 바로 리액트의 createElement라는 함수이다.

class Hello extends React.Component {
	render() {
    	return <div>Hello {this.props.toWhat}</div>;
    }
}

ReactDOM.render(
	<Hello toWhat="World" />,
    document.getElementById('root')
 );

 

이 코드를 보면 hello라는 이름을 가진 React 컴포넌트가 나오고 컴포넌트 내부에서 JavaSciprt 코드와 HTML 코드가 결합된 JSX를 사용하고 있는 것을 볼 수 있다. 그리고 이렇게 만들어진 컴포넌트를 React DOM의 렌더 함수를 사용해서 실제 화면에 렌더링하고 있다.

class Hello extends React.Component {
	render() {
    	return React.createElement('div', null, 'Hello ${this.props.toWhat}');
    }
}

ReactDOM.render(
	React.createElement(Hello, { toWhat: 'World' }, null),
    document.getElementById('root')
 );

 

방금 전에 살펴본 코드와 거의 비슷하게 생겼다. 이 코드는 JSX를 사용하지 않고 순수한 JavaScript 코드만을 사용해서 방금 전에 우리가 봤던 코드와 완전히 동일한 역할을 하게 하는 만든 코드이다.

두 코드를 비교해 보면 Hello 컴포넌트 내부에서 JSX를 사용했던 부분이 react.createElement라는 함수로 대체된 것을 알수 있다. 결국 JSX 문법을 사용하면 React에서는 내부적으로 모두 createElement라는 함수를 사용하도록 변환하게 되는 것이다. 그리고 최종적으로 이 createElement함수를 호출한 결과로 JavaScript 객체가 나오게 된다.

// JSX를 사용한 코드
const element = (
	<h1 className="greeting">
    	Hello, world!
    </h1>
)

// JSX를 사용하지 않은 코드
const element = React.createElement(
	'h1',
    { className: 'greeting' },
    'Hello, world!'
)

 

이 두 개의 코드는 JAX를 사용한 코드와 사용하지 않은 코드이며 모두 동일한 역할을 한다.

JSX를 사용한 코드도 내부적으로 createElement함수를 사용하도록 변환되기 때문이다.

그리고 이 createElement함수 호출의 결과로 이 코드와 같은 JavaScript객체가 나오게 된다.

React는 이 객체들을 읽어서 DOM을 만드는데 사용하고 항상 최신 상태로 유지한다.

React에서는 이 객체를 element라고 한다.

(element에서는 뒤에서 더 자세히 배울 예정)

 

그렇다면 createElement 함수의 파라미터로는 어떤 것이 들어갈까?

React.createElement(
	type,
    [props],
    [...children]
)

이 코드는 createElement 함수의 파라미터를 나타낸 것이다.

먼저 첫번째 파라미터는 엘리먼트의 유형, 타입을 나타낸다.

이 유형으로 div나 span같은 html 태그가 올 수도 있고, 다른 React 컴포넌트가 들어갈 수 있다.

 

두번째 파라미터로는 props가 들어가게 된다.

우리가 아직 React컴포넌트의 props라는 개념에 대해 배우지 않았기 때문에 일단은 속성들이 들어간다고 기억하면 된다.

 

마지막 세번째 파라미터로는 children이 들어가는데, 여기에서 children이란 현재 엘리먼트가 포함하고 있는 자식 엘리먼트라고 보면 된다.

 

리액트는 이런식으로 JSX코드를 모두 createElement함수를 사용하는 코드로 변환한다.

그렇기 때문에 React에서 JSX를 사용하는 것이 필수는 아니다

왜냐하면 직접 모든 코드를 createElement함수를 사용해서 개발하면 되기 때문이다.

다만 JSX를 사용했을 때 코드가 더욱 간결해지고 생산성과 가독성이 올라가기 때문에 사용하는 것을 권장한다.

 

JSX의 장점

1. 코드가 간결해진다.

// JSX를 사용한 코드
<div>Hellom, {name}</div>

// JSX를 사용하지 않은 코드
React.createElement('div', null, 'Hello, ${name}');

화면에서는 JSX를 사용한 코드와 사용하지 않은 두 개의 코드를 보여주고 있다.

이 두개의 코드는 모두 동일한 역할을 한다.

JSX를 사용한 코드의 경우 HTML의 div 태그를 사용해서 name이라는 변수가 들어간 인삿말을 표현하고있다.

그리고 아래의 있는 JSX를 사용하지 않은 코드의 경우 React의 createElement 함수를 사용하여 동일한 작업을 수행하게 된다.

앞에서 배운 것처럼 type props children이라는 createElement 파라미터들을 사용하고 있는 것을 볼 수 있다.

 

2. 가독성 향상

// JSX를 사용한 코드
<div>Hellom, {name}</div>

// JSX를 사용하지 않은 코드
React.createElement('div', null, 'Hello, ${name}');

예제 코드를 다시 보면 JSX를 사용한 코드가 그렇지 않은 코드에 비해 코드의 의미가 훨씬 더 빠르게 와닿는 것을 볼 수 있다. 가독성은 코드를 작성할 때 뿐만 아니라 유지 보수 관점에서도 굉장히 중요한 부분이다.

가독성이 높을수록 코드상에 존재하는 버그 또한 쉽게 발견할 수 있기 때문이다.

이처럼 JSX를 사용하게 되면 가독성이 올라간다.

 

3. Injection Attacks 방어

JSX를 사용하는 것의 세 번째 장점은 인젝션 어택이라 불리는 해킹 방법을 방어함으로써 보안성이 올라간다는 것이다.

인젝션 어택은 쉽게 말해서 입력창에 문자나 숫자같은 일반적인 값이 아닌 소스 코드를 입력하여 해당 코드가 실행되도록 만드는 해킹 방법이다.

const title = response.potentiallyMaliciousInput;

// 이 코드는 안전하다.
const element = <h1>{title}</h1>;

이 코드에는 title이라는 변수에 잠재적으로 보안 위험 가능성이 있는 코드가 삽입되었다.

그리고 그 아래에 나오는 JSX 코드에서는 괄호를 사용해서 타이틀 변수를 삽입, 인베딩하고 있다.

기본적으로 React DOM은 렌더링하기 전에 인베딩된 값을 모두 문자열로 변환한다. 그렇기 때문에 명시적으로 선언되지 않은 값은 괄호 사이에 들어갈 수 없다.

이것은 결과적으로 XSS라 불리는 크로스 사이트 스크립팅 어택을 방어할 수 있다.

이처럼 JSX를 사용하면 잠재적인 보안 위협을 줄일 수 있다는 장점이 있다.

 

그렇다면 JSX는 어떻게 사용할까?

 JSX 사용법

기본적으로 JSX는 자바스크립트 문법을 확장시킨 것이기 때문에 모든 자바스크립트 문법을 지원한다.

여기에 추가로 XML과 HTML을 섞어서 사용하면 된다.

const name = '코딩가득';
const element = <h1>안녕, {name}</h1>;

ReactDOM.render(
	element,
    document.getElementById('root')
);

위에 코드에서 엘리먼트를 선언하는 부분의 코드처럼 HTML과 자바스크립트가 섞인 형태로 코드를 작성하면 된다.

xml, html 코드를 사용하다가 중간에 JavaScript코드를 사용하고 싶으면 중괄호를 써서 묶어주면 된다.

... XML / HTML

{JavaScript 코드}

... XML / HTML

 

 

그렇다면 HTML 태그 중간이 아닌 태그의 속성에 값을 넣고 싶을 때에는 어떻게 해야할까?

// 태그의 속성(attribute)에 값을 넣는 방법

// 큰따옴표 사이에 문자열을 넣거나
const element = <div tabIndex="0"></div>;

// 중괄호 사이에 자바스크립트 코드를 넣으면 된다.
cosnt element = <img src={user.avatarUrl}></img>;

이 코드처럼 큰 따옴표 사이에 문자열을 넣거나 중괄호 사이에 자바스크립트 코드를 넣으면 된다.

그래서 JSX에서는 중괄호를 사용하면 무조건 자바스크립트 코드가 들어간다라고 외워두는 게 좋다.

 

마지막으로 JSX를 사용해서 children을 정의하려면 어떻게 해야 될까?

// 자식(children)을 정의하는 방법
const element = (
	<div>
    	<h1>안녕하세요</h1>
        <h2>열심히 리액트를 공부해 봅시다!</h2>
    </div>
);

이 코드처럼 우리가 평소에 HTML을 사용하듯이 상위 태그가 하위 태그를 둘러싸도록 하면 자연스럽게 children이 정의된다.

여기에서 div태그의 children은 h1태그와 h2태그가 된다.
이처럼 가독성도 높으면 간결하고 직관적으로 코드를 작성할 수 있게 해주는 것이 바로 JSX의 역할이라고 볼 수 있다.

 

실습

(해당 실습은 리액트 애플리케이션이 깔려있다는 전제하에 진행합니다.)

my-app>src>chapter_03 폴더를 만들고 Book.jsx 파일 생성

import React from "react";

// Book이라는 컴포넌트를 생성
// Book 컴포넌트는 props로 name과 numOfPage를 받아서 이를 출력하는 컴포넌트이다.
function Book(props) {
    return (
        <div>
        	// 홀따옴표(')가 아닌 억음부호(`) 이다.
            <h1>{`이 책의 이름은 ${props.name}입니다.`}</h1>
            <h2>{`이 책은 총 ${props.numOfPage}페이지로 이뤄져 있습니다.`}</h2>
        </div>
    );
}

export default Book;

Book.jsx 파일에 해당 코드 입력.

chapter_03 폴더에 Library.jsx 파일 생성

import React from "react";
import Book from "./Book";

// Library라는 이름의 react 함수 컴포넌트 생성
// Library 컴포넌트는 총 3개의 Book 컴포넌트를 렌더링하고 있다.
function Library(props) {
    return (
        <div>
            <Book name="처음 만난 파이썬" numOfPage={300} />
            <Book name="처음 만난 AWS" numOfPage={400} />
            <Book name="처음 만난 리액트" numOfPage={500} />
        </div>
    );
}

export default Library;

Library.jsx에 해당 코드 입력.

 

다음으로 우리가 만든 컴포넌트를 실제로 화면에 렌더링하기 위해 index.js 파일을 수정해야한다.

(기본 index.js 파일 코드)

※ 주의

강의에서 나온 코드로 진행하면 ReactDOM.render에 취소선(해당 코드를 권장하지 않는다는 뜻)이 생긴다.

 

 

아래의 코드로 수정 (2024.05-07 기준)

import React from 'react';
import ReactDOM from 'react-dom/client'; // React 18 업데이트 이후 '/client' 경로 추가
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import Library from './chapter_03/Library';

// React 18에서 새로운 root API 사용
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Library />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

해당 코드로 변경했을 때 취소선이 사라지는 것을 볼 수 있다.

React 18 업데이트 이후로 react-dom 뒤에 /client 경로가 추가 됐고 API의 사용법도 달라졌다고 한다.

React 18에서는 ReactDOM.render의 사용이 더 이상 권장되지 않으며, 이는 React의 새로운 기능인 동시 모드(Concurrent Mode)를 사용하기 위함과 API 일관성을 유지하기 위한 변경사항 중 하나입니다. 이러한 변경사항으로 인해 ReactDOM.render 대신 새로운 루트 API를 사용하는 것이 권장됩니다.

 

ReactDOM.render는 React 18에서도 이전 버전과의 호환성을 위해 계속 작동하지만, React 18의 새로운 기능과 개선 사항을 활용하기 위해서는 새로운 루트 API로 전환하는 것이 권장한다고 하니 최신 버전의 코드로 진행하도록 하자.

 

 

수정한 내용은 import문을 사용해서 방금 만든 라이브러리 컴포넌트를 가져온 뒤에 react-dom을 사용하여 root-dom노드에 렌더링하도록 하는 코드이다.

모든 코드 작성이 끝났다면 실제로 react 애플리케이션을 실행해 보도록 하자.

 

vscode의 상단 메뉴에서 terminal-new-terminal을 눌러서 새로운 터미널을 하나 실행시킨다.

이후 그림처럼 npm start 명령어를 실행.

 

3000포트로 접속해서 로컬에서 돌아가는 지 확인.

 

해당 페이지가 나온다면 정상적으로 작동된 것이다.

 

참고 강의 : 처음 만난 리액트(React)