들어가기 전 JS와 JSX는 무엇이
, 어떻게
다를까? 먼저 코드 생김새부터 봐보자.
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')
);
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 공식 홈페이지를 찾아보았다.
🗣️ 결론적으로 필수도 아니고 큰 차이는 없지만, "JSX를 사용하면 자바스크립트 내에서 직관적으로 UI 관련 작업이 가능하고 개발에 도움을 주는 에러 및 경고 메세지를 표시할 수 있게 해준다" 정도로 정리할 수 있을 것 같다.
JSX란 JavaScript XML(eXtensible Markup Language)의 약어로, JavaScript에 XML을 추가한 확장된 문법이다.
const element = <h1>Hello, world!</h1>;
div
, span
과 같은 HTML 태그를 사용해 작성할 수 있다.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} />;
💡 속성 정의 방법
- 따옴표를 사용하여 문자열 입력 → 정적
- 중괄호를 사용하여 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>
);
}
}
특정 조건을 만족할 때만 해당 요소를 보여주고 싶을 때 사용한다.
class App extends Component {
render() {
let name = "React";
return <div>{name === "React" && <h1>This is React.</h1>}</div>;
}
}
undefined
나 null
을 반환하면 렌더링 시 오류가 발생한다.undefined
나 null
을 렌더링 하는 것은 괜찮다. 단 오류만 발생하지 않을 뿐, 렌더링 시 아무것도 보여주지 않는다.undefined
나 null
일 경우 보여주고 싶은 요소가 있을 때 사용한다.class App extends Component {
render() {
let name = undefined;
return <div>{name === "React" || <h1>This is React.</h1>}</div>;
}
}
HTML 엘리먼트에서 속성을 정의할 수 있는 것처럼, JSX에서도 엘리먼트의 속성을 정의할 수 있다.
하지만 JSX는 HTML 보다는 JavaScript에 좀 더 가깝기 때문에, HTML 엘리먼트에 속성을 정의하는 방식과는 약간 다르게 정의한다.
JSX가 반환하는 React DOM Element에서는 기존 HTML 속성이 아닌 CamelCase로 작성된 속성명을 사용해야 한다.
/*
class → className
background-color → backgroundColor
font-size → fontSize
*/
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>
);
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 Element" 라고 하며, 이는 화면에 표시하려는 항목에 대한 설명을 뜻한다.
React는 React Element객체를 통해 DOM을 구성하고 최신으로 유지하는 데 사용한다.
브라우저는 HTML, CSS, JS 문서의 코드만 이해할 수 있기 때문에 리액트에서 작성한 JSX문법은 브라우저가 이해할 수 없다.
따라서 리액트에서 작성된 JSX 코드를 브라우저가 이해할 수 있는 JS 코드로 변환하는 과정이 필요하게 되었다.
그리고 대표적인 변환 과정 2가지를 설명해보려 한다.
Node.js와 그 외 빌드 툴 등으로 구성된 개발 환경을 구축하여 리액트로 개발하는 것
빌드 툴을 이용해 JSX로 작성된 코드들이 JS로 변환되며, 다른 일반적인 JS파일처럼 참조할 수 있도록 변환된 파일디 디스크에 저장되다.
런타임 시 브라우저가 JSX를 JS로 자동 변환하게 하는 방법
CDN을 이용하는 방식으로, 일반 JS처럼 JSX를 직접 지정하면 브라우저가 알아서 처리한다.
브라우저가 실행할 때 CDN으로 연결한 스크립트 파일 하나만 참조하고, 그 스크립트 파일은 페이지가 로딩될 때 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
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가 완성되면, 브라우저는 해당 문서를 읽어 작성된 코드가 화면에 출력된다.
📂 참고문서