[20240116 TIL] JS와 JSX

Haizel·2024년 1월 17일
1
post-thumbnail

00. JS vs JSX (Off-the-record)


들어가기 전 JS와 JSX는 무엇이, 어떻게 다를까? 먼저 코드 생김새부터 봐보자.

① JS

class Hello extends React.Component {
	render() {
		return React.createElement("div", null, "Hello", this.props.name);
	}
}

ReactDOM.render(
	React.createElement(Hello, {name, "World"}),
	document.getElementById('container')
);

② JSX

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

RectDOM.render(
	<Hello name="World" />,
	document.getElementById('container');
);

📂 .js.jsx

위 코드들을 통해 JS와 JSX코드의 문법이 살짝 다른건 확인했다. 그럼 파일 확장자명 .js.jsx는 뭐가 다른걸까?

나와 같은 의문을 품는 사람들이 많은지, StackOverFlow에도 비슷한 질문이 올라왔다.

[질문]

.js를 사용하는 많은 예시가 있지만, .jsx 또한 많이 사용되는 것 같습니다. 저는 jsx 관련 문서를 읽었고, Javascript 안에 HTML을 사용할 수 있다는 점을 알게 되었습니다. 그렇다면 실질적으로 .js.jsx의 차이점은 어떻게 되나요?

[답변]

.js.jsx는 확장자로서의 차이점은 없으나, JSX가 표준 자바스크립트 문법이 아닌 만큼, Plain하지 않은 자바스크립트가 JS 파일에 들어가는 것에 대한 논쟁에 있을 수 있습니다.

❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓❓

무언가 답변이 명쾌하지 않다. 그래서 React 공식 홈페이지를 찾아보았다.

💎 React 공식 홈페이지

🗣️ 결론적으로 필수도 아니고 큰 차이는 없지만, "JSX를 사용하면 자바스크립트 내에서 직관적으로 UI 관련 작업이 가능하고 개발에 도움을 주는 에러 및 경고 메세지를 표시할 수 있게 해준다" 정도로 정리할 수 있을 것 같다.


01. JSX란


JSX란 JavaScript XML(eXtensible Markup Language)의 약어로, JavaScript에 XML을 추가한 확장된 문법이다.

const element = <h1>Hello, world!</h1>;
  • JSX는 React Element를 생성한다. React Element는 브라우저 DOM 엘리먼트와 달리 일반 객체이다.
  • React에서 JSX 사용이 필수는 아니지만, JSX를 사용하면 JS 코드 안에서 UI 관련 작업을 할 수 있기 때문에 시각적으로 더 도움이 된다.
  • JSX를 사용하면 React에게 더 도움이 되는 에러 및 경고 메세지를 표시할 수 있게 해준다.

💎 JSX 장점

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

02. JSX 규칙


💎 문법 규칙

① 반드시 부모 요소 하나가 감싸는 형태여야 한다.

Virtual DOM에서 컴포넌트 변화를 감지할 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다는 규칙이 있다.

② 자바스크립트 표현식 사용하기

JSX에서는 중괄호 {}를 사용해 자바스크립트 표현식을 사용할 수 있다.

import React from 'react';

function App(){
	const name = 'react';
	return(
    	<>
          <h1>Hello! {name}</h1>
          <h2>Is it working well?</h2>
        <>
    )
}

export default App;

❗️이때 따옴표를 사용하지 않는다.

  • JSX에서 JS 표현식을 사용해 속성값을 정의할 땐, 따옴표를 사용하지 않는다.
// 속성값 정의 시 JS 표현식을 사용고자자 할 경우 따옴표를 사용하지 않는다.
const element = <img src={user.avatarUrl} />;

💡 속성 정의 방법

  1. 따옴표를 사용하여 문자열 입력 → 정적
  2. 중괄호를 사용하여 JS표현식 사용. 이 경우에는 따옴표를 사용하지 않음 → 동적

✷ 속성값을 정의 할 경우 위 두 가지 방법 중 하나만 사용해야 하며, 동일한 속성에 위 두가지 방법을 사용할 수 없다. 한 속성에 하나의 방식만 사용해야 한다.

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

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 연산자 (||)

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

💎 속성 정의 규칙

HTML 엘리먼트에서 속성을 정의할 수 있는 것처럼, JSX에서도 엘리먼트의 속성을 정의할 수 있다.
하지만 JSX는 HTML 보다는 JavaScript에 좀 더 가깝기 때문에, HTML 엘리먼트에 속성을 정의하는 방식과는 약간 다르게 정의한다.

① CamelCase 표기법으로 작성

JSX가 반환하는 React DOM Element에서는 기존 HTML 속성이 아닌 CamelCase로 작성된 속성명을 사용해야 한다.

/*
class → className
background-color → backgroundColor
font-size → fontSize
*/

② 인라인 스타일링(In-line Style)

JSX에서는 Style 속성 안에 직접 CSS를 포함할 수 없으며, 스타일 정보를 담은 객체를 참조해야 한다. 스타일 객체의 경우, 기존 CSS 속성 명을 CamelCase로 작성한다.

// JXS에서 CSS를 적용하기 위해서는 스타일 객체를 만들어야 한다.
const styleObject = {
  color: "#333",
  padding: 0,
  backgroundColor: "black", // 스타일 각체의 속성은 모두 camelCase로 작성한다.
  fontSize: "32",
};

const element = <div style={styleObject}>Hello World</div>;

//--------------------------------------------------------------------

// 스타일 객체를 style 속성 내부에 선언 가능
const element = (
  <div style={{ color: "#333", fontSize: "32" }}>Hello World</div>
);

03. JSX의 특징


① 대소문자를 구별한다.

JSX에서 HTML 엘리먼트를 작성할 때는 만드시 소문자를 사용해야 하지만, 컴포넌트를 작성할 때는 컴포넌트 클래스와 동일하게 PascalCase로 작성해야 한다.

ReactDOM.render(
  <div>
    <MyCustomComponent />
  </div>,
  document.getElementById("root"),
);

② 주입 공격을 방지한다.

기본적으로 React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프 처리하므로 애플리케이션에서 명시적으로 작성되지 않은 내용은 주입되지 않는다. 또한 모든 항목은 렌더링되기 전에 문자열로 변환된다.

이러한 특징으로 XSS(Cross-site-scripting) 공격을 방지할 수 있다.

③ 객체를 표현한다.

Babel은 JSX를 React.createElement() 호출로 트랜스파일한다.

❶ 개발자가 작성한 코드 → Babel이 트랜스파일

// 개발자가 작성한 코드
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 Element 생성

이러한 일련의 과정을 거쳐 생성된 객체를 "React Element" 라고 하며, 이는 화면에 표시하려는 항목에 대한 설명을 뜻한다.

React는 React Element객체를 통해 DOM을 구성하고 최신으로 유지하는 데 사용한다.


04. JSX 변환 과정


💎 변환 과정은 왜 필요한가?

브라우저는 HTML, CSS, JS 문서의 코드만 이해할 수 있기 때문에 리액트에서 작성한 JSX문법은 브라우저가 이해할 수 없다.

따라서 리액트에서 작성된 JSX 코드를 브라우저가 이해할 수 있는 JS 코드로 변환하는 과정이 필요하게 되었다.

그리고 대표적인 변환 과정 2가지를 설명해보려 한다.

✅ Build Tool 이용하기

Node.js와 그 외 빌드 툴 등으로 구성된 개발 환경을 구축하여 리액트로 개발하는 것

빌드 툴을 이용해 JSX로 작성된 코드들이 JS로 변환되며, 다른 일반적인 JS파일처럼 참조할 수 있도록 변환된 파일디 디스크에 저장되다.

  • 장점
    • 현재 웹 개발에서 사용되는 대표적인 방식으로 JSX → JS로 트랜스파일 된다.
    • 여러 모듈과 빌드 툴, 그리고 그 외 복잡한 웹앱의 관리에 필요한 많은 기능을 이요할 수 있다.
  • 단점
    • 초기 개발 환경 세팅이 약간 복잡하고 시간이 걸린다.

☑️ Run-Time 자동 변환 이용하기

런타임 시 브라우저가 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 변환 과정 엿보기

① Babel로 트랜스파일링

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를 사용하면 훨씬 쉽고 편하게 UI를 렌더링할 수 있다.

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

작성한 JSX 코드를 화면에 렌더링하기 위해선 ReactDOM.render() 함수를 사용해야 한다.

ReactDOM.render() : 컴포넌트를 페이지에 렌더링하는 역할을 하며, React-DOM Module을 불러와 사용할 수 있다.

  • element : JSX로 작성한 화면에 출력할 내용
  • container : 첫 번째 인자인 JSX를 렌더링해서 보여줄 DOM 안의 위치
ReactDom.render(<h1>Hello World</h1>, document.body);

render 함수의 결과로 최종 HTML, CSS, JS가 완성되면, 브라우저는 해당 문서를 읽어 작성된 코드가 화면에 출력된다.



📂 참고문서

profile
한입 크기로 베어먹는 개발지식 🍰

0개의 댓글

관련 채용 정보