[스터디-우아한반상회] JSX

rladpwl0512·2022년 5월 8일
5

JSX란?

개념

const element = <h1>Hello, world!</h1>;
  • JSX 문법은 Javascript에 XML을 추가한 Javascript 확장 문법이다. 따라서, Javascript의 모든 기능이 포함되어있다.
    React에서는 JSX 문법을 사용해서 하나의 파일에서 Javascript, html을 작성하여 컴포넌트를 구성한다.
    🤔 XML이란?
    마크업언어이다. 데이터를 저장, 전송을 목적으로 디자인 된 언어이다. HTML은 정해진 태그가 있지만, XML은 사용자 정의 태그를 사용한다.
<!-- HTML -->

<div>
  <h1>고양이</h1>
</div>



<!-- XML -->
<CAT>
  <NAME>Izzy</NAME>
  <BREED>Siamese</BREED>
  <AGE>6</AGE>
  <ALTERED>yes</ALTERED>
  <DECLAWED>no</DECLAWED>
  <LICENSE>Izz138bod</LICENSE>
  <OWNER>Colin Wilcox</OWNER>
</CAT>

JSX의 특징

JSX문법은 브라우저에서 실행되기 전, javascript로 변환이 되어야 브라우저에서 동작할 수 있다.

babel이 이 역할을 해준다. babel을 통해 JSX문법이 Javascript 코드로 변환된다.
babel은 JSX를 React.createElement() 호출로 컴파일한다.

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

위 코드를, Babel은 다음과 같이 변환한다.

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);


React.createElemnt()는 다음과 같은 객체를 생성한다.
이와 같이 JSX를 React.createElement로 변환하는 과정을 통해, JSX는 React 엘리먼트를 생성한다.

🤔 엘리먼트는 화면에 표시할 내용을 기술하는 react 앱의 가장 작은 단위이다. 이걸 생성한다고해서 렌더링 되는 것은 아니고 ReactDOM.render 내부에 이 엘리먼트를 넣어줘야 화면에 렌더링된다.

const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

🤔 React.createElemnt() vs document.createElement() 다른점은? (추가 필요!)
리액트에서는 document.createElement()가 아닌, React.createElemnt()를 사용한다. 비슷하게 생겼는데, 똑같은거 아닌가?
document.createElement()의 경우에는, dom 요소를 반환한다.
하지만, React.createElement는 dom 요소를 나타내는 객체를 반환한다.
+스터디에서 document.createElement()가 내부에 엄청 많은 정보들을 담고 있다는 이야기가 나왔다(React.createElement가 포함하는 객체 포함).
여기에 대해선 추가적으로 공부해 볼 예정이다.

🤔 그렇다면 react에서는 왜 객체를 반환하는 React.createElement를 사용해야할까? (추가 필요!)
리액트는 가상 DOM을 실행한다. 가상 DOM은 real DOM보다 가볍고, 훨씬 더 빠른 rendering이 가능하다. 그래서 가상 DOM을 사용하는 react는 '빠르다'는 장점이 있다.
참고

JSX를 통해 하나의 파일에 자바스크립트, html을 동시에 작성해서 편리하다.

우리가 vanilla javascript로 웹페이지를 개발했을 때에는, 마크업 코드는 .html파일에, 로직 코드는 .js 파일에 분리를 해서 작성했다.
하지만 react는 마크업과 로직이 연결되어있다고 생각하고, 별도의 파일에 마크업, 로직 코드를 따로 따로 작성하는 대신 '컴포넌트' 내부에서 마크업과 로직 코드를 모두 포함시킨다.

JSX 중괄호 내부에는 모든 Javascript 표현식을 넣을 수 있다.

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

🤔 JSX 중괄호 내에 반복문(for문), 조건문(if문)을 넣을 수 있을까?
JSX 중괄호 내에는 '표현식' 만 넣을 수 있다. 반복문, 조건문과 같이 '문'을 JSX 코드에 단순 삽입하는 것은 불가능하다.
따라서, 보통 if문 대신 삼항 연산자 및 논리연산자를 사용하고, for문 대신 map을 사용한다.
정말 정말 if문, for문과 같은 문을 사용하고 싶다면 함수 내부에서 구현해주면 되지만 함수 내부에서 즉시 실행 함수로 만들어 줘야하기 때문에 매우 지저분해진다. 따라서 JSX에서 문을 함수로서 사용하는 방식은 지양하자!

  • 조건문 사용하기
function App() {
  	const test = 1; 
  
	return (
    	<div>
        	{test === 1? '1입니다' : '1이 아닙니다'}
        </div>
    )
}
function App() {
  	const test = 1; 
  
	return (
    	<div>
        	{
        		(function() {
                  if(test === 1) {
                    return '1입니다';
                  } else {
                  	return '1이 아닙니다';
                  }
                })()
        	}
        </div>
    )
}

// 화살표 함수도 가능하다! 
function App() {
  const test = 1;

  return (
    <div>
      {(() => {
        if (test === 1) {
          return '1입니다';
        } else {
          return '1이 아닙니다';
        }
      })()}
    </div>
  );
}
  • 반복문 사용하기
function App() {
  const test = [1, 2, 3];

  return (
    <div>
      {test.map((item) => (
        <span>{item}</span>
      ))}
    </div>
  );
}

🤔 반복문 대신 map을 사용한다고 하는데, 그렇다면 forEach는 사용할 수 없는가?

위의 코드를, forEach로 사용하면 안될까?
먼저 map과 forEach의 차이점을 생각해보자. map은 반복문을 돌려서 새로운 배열을 만들어내고, forEach는 undefined를 반환한다.
jsx 내부에서 forEach를 쓰면, 결국 아무것도 반환하지 않아서 렌더링이 되지 않는것이다. 따라서, JSX 안에서 컴포넌트로 들어가기 위해서는 결과값을 뱉어내는 map을 사용해야한다!

function App() {
  const test = [1, 2, 3];

  return (
    <div>
      {test.forEach((item) => (
        <span>{item}</span>
      ))}
    </div>
  );
}

JSX는 babel로 변환되면 결국 javascript 객체가 된다. 따라서, JSX는 if 구문 및 for문 안에서 사용될 수 있고, 변수에 할당될 수 있고, 인자로 받아들여질 수 있고, 함수로부터 반환될 수 있다.

function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}

html 어트리뷰트에서 중괄호를 사용하면 Javascript 표현식을 삽입할 수 있다. 단 이때, 중괄호 주변에 따옴표를 입력하면 안된다.

const element = <img src={user.avatarUrl}></img>;

JSX에 사용자 입력을 삽입하더라도, XSS 공격으로부터 안전하다.

JSX의 규칙


babel에서 JSX가 Javascript로 제대로 변환되기 위해서 지켜줘야하는 몇가지 규칙이 있다.

태그는 꼭 닫혀야한다

import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
      <Hello />
      <Hello />
      <input> <!-- 에러! -->
      <br> <!-- 에러! -->
    </div>
  );
}

export default App;

html에서는 input, br이 단일태그로서 닫힌태그를 생략해도 됐지만, JSX에서는 반드시 닫아줘야한다.
또한 위에서 <Hello /> 쓴 것과 같이, self closing을 사용해서 닫힌 태그를 표현해줄 수 있다. 열린 태그, 닫힌 태그 내부에 내용이 들어가지 않을 때 self closing을 사용할 수 있다.

두개 이상의 태그는 꼭 감싸져야한다

import Hello from './Hello';

function App() {
  return (
    <Hello />
    <div>안녕히계세요.</div>
  );
}

export default App;

위 코드는 에러가 나타난다.

그래서, 예를들어 div 태그를 만들어서 두개의 태그를 감싸주면 위 에러는 사라진다. 하지만, 의미없이 넣는 div 태그는 좋지 않다. 이때 react의 fragment를 사용하면 된다. fragment는, 브라우저 상에서 별도의 엘리먼트로 나타나지 않는다.

import Hello from './Hello';

function App() {
  return (
    <>
      <Hello />
      <div>안녕히계세요.</div>
    </>
  );
}

export default App;

JSX 내부에서 자바스크립트의 값을 사용하고 싶을 땐 중괄호 사용하기

import React from 'react';
import Hello from './Hello';

function App() {
  const name = 'react';
  return (
    <>
      <Hello />
      <div>{name}</div>
    </>
  );
}

export default App;

style과 className

  • JSX는 html 태그 내부에서 style 속성값을 넣을 때, 예를 들어 background-color가 아닌 camel case로 backgroundColor와 같이 사용해야한다.

  • JSX는 html보다는 javascript에 가까운 문법이다. 따라서, html 태그 내부에서 class를 사용하면 이 class를 javascript의 예약어 class로 인식한다. 따라서, html 태그 내부에서는 class 대신 className을 사용한다.

위와 같이 작성하지 않으면, 에러를 만나게 된다!

  • 주석
import React from 'react';
import Hello from './Hello';
import './App.css';


function App() {
  const name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24, // 기본 단위 px
    padding: '1rem' // 다른 단위 사용 시 문자열로 설정
  }

  return (
    <>
      <Hello />
      <div style={style}>{name}</div>
      <div className="gray-box"></div>
    </>
  );
}

export default App;

주석

function App() {
  return (
    <>
      {/* 주석은 화면에 보이지 않습니다 */}
      /* 중괄호로 감싸지 않으면 화면에 보입니다 */
      <div 
        // 열리는 태그 내부에서는 이렇게 주석을 작성 할 수 있습니다.
      />
    </>
  );
}

📚 참고


✅ 점검

  • JSX가 변환된 모습
  • if-else는 왜 사용할 수 없을까?
  • map은 되는데 for는 왜 안될까?
  • forEach를 사용할 수 있을까?
  • JSX와 표현식은 같을까요?
  • JSX와 React.createElement() 는 무슨 관계일까요?
  • document.createElement()와 다른 점은 무엇일까요?
  • 값, 식, 문
  • 가상돔
  • html, xml
profile
내가 짱이다 😎 매일 조금씩 성장하기🌱

0개의 댓글