JSX란?
const element = <h1>Hello, world!</h1>;
- 위에 태그 문법은 문자열도, HTML도 아닌 JSX(JavaScript XML)라는 JavsScript에 XML을 추가하여 확장한 문법
- JSX는 React "엘리먼트(element)"를 생성. React 엘리먼트는 브라우저 DOM엘리먼트와 달리 일반 객체임
- React는 JSX 사용이 필수가 아니지만, JS 코드 안에서 UI관련 작업을 할 수 있기 때문에 시각적으로 더 도움이 됨. 또한 JSX를 사용하면 React가 더욱 도움이 되는 에러 및 경고 메시지를 표시할 수 있게 해줌.
JSX 사용하기
- 어떤 프레임워크를 사용해 웹앱을 만들 때 가장 중요한 것은 최종결과가 HTML, CSS, JS의 조합이어야 함. (그렇지 않으면 브라우저가 이해 못함)
- 리액트로 개발을 할 때 HTML, CSS, JS 코드를 작성하기도 하지만 상당부분을 JSX로 코드를 작성해야 함.그러나 JSX는 공식적인 JS문법이 아니기 때문에 브라우저는 JSX를 이해하지 못함. 때문에 리액트로 개발을 할 때는 JSX를 브라우저가 이해할 수 있는 평범한 자바스크립트로 변환시킬 방법이 필요함.
- Node.js와 그 외 빌드 툴 등으로 구성된 개발환경을 구축하여 리액트로 개발하는 것
- 빌드 툴을 이용해 JSX로 작성된 코드들이 JS로 변환되며, 다른 일반적인 JS 파일처럼 참조할 수 있도록 변환된 파일이 디스크에 저장된다.
- 장점 : 오늘날 현대적인 웹개발에서 대표적인 방식, JSX에서 JS로 트랜스 파일 됨. 여러 모듈과 빌드 툴 그리고 그 외 복잡한 웹앱의 관리에 필요한 많은 기능 이용 가능
- 단점 : 처음에는 약간 복잡하고 시간이 걸림
- 런타임 시 브라우저가 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">
</script>
JSX 변환 과정
- JSX는 브라우저에서 실행되기 전에 코드가 번들링되는 과정에서 바벨을 사용하여 자바스크립트 형태로 변환됨.
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
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 장점
- 보기 쉽고 익숙하다.
- JSX는 HTML 코드와 비슷하기 때문에 일반 자바스크립트만 사용한 코드보다 더 익숙하며 가독성이 좋다.
- 높은 활용도
- 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태그의 사용을 막고 스타일 관련 코드가 꼬이지 않게 방지하기 위함이다. 이를 위해 리액트에서는 복수의 엘리먼트를 리턴하는 방법을 제공한다.
복수 엘리먼트 리턴
- 배열 문법 사용
ReactDOM.render(
[
<div key="1">Hello</div>,
<div key="2">Bye</div>
],
document.getElementById('root')
);
- 리액트 v16.2.0 부터 추가된 프래그먼트(Fragment)패턴 사용
ReactDOM.render(
<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에게 알려준다.
- 각 엘리먼트들이 배열에 담겨져 있는 것이 아니므로 쉼표나 구분자가 필요 없다.
- eky속성과 고유값을 지정할 필요가 없다.
JS 표현식 사용하기
- JSX에서는 중괄호 { } 를 사용하여 JS 표현식을 쓸 수 있다.
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
ReactDOM.render(
<p>Random number : {Math.random() * 100}</p>,
document.getElementById('root')
);
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 엘리먼트에 속성을 정의하는 방식과는 약간 다른 방식으로 속성을 정의한다.
- JSX가 반환하는 React DOM 엘리먼트에서는 기존 HTML 속성이 아닌 camelCase로 작성된 속성명을 사용해야 한다. 예를 들어 JSX에서 class는 className이 되고 tabindex는 tabIndex가 된다.
- className이 아닌 class 값을 설정 시 스타일이 설정은 되지만 경고 문구가 뜬다. 하지만 v16 이상 부터는 class를 className으로 변환시켜주고 경고를 띄워준다.
- JSX에서 속성값을 정의 할 때 중괄호 {}를 사용하여 JS 표현식을 사용할 수 있는데 이 경우 따옴표를 사용하지 않는다.
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}/>;
- 속성값 정의 방법
- 따옴표를 사용하여 문자열 입력 -> 정적
- 중괄호를 사용하여 JS표현식 사용. 이 경우에는 따옴표를 사용하지 않음. -> 동적
- 속성값을 정의할 경우 위 두 가지 방법 중 하나만 사용해야 하며, 동일한 속성에 위 두가지 방법을 사용할 수 없다. 한 속성에 하나의 방식만 사용해야 한다.
인라인 스타일링
- JSX에서는 style 속성 안에 직접 CSS를 포함할 수 없으며, 스타일 정보를 담은 객체를 참조해야 한다. 스타일 객체의 경우 기존 CSS 속성 명을 camelCase로 작성한다.
var element = <div style="color:red;">Hello World</div>;
var styleObject = {
color: "#333",
padding: 0,
backgroundColor: "black",
fontSize: "32"
}
var element = <div style={styleObject}>Hello World</div>;
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>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
- React.createElement()는 버그가 없는 코드를 작성하는데 도움이 되도록 몇 가지 검사를 수행 후, 기본저긍로 다음과 같은 객체를 생성한다.
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
}
- 이렇게 생성된 객체를 "React 엘리먼트"라고 하며, 이는 화면에 표시하려는 항목에 대한 설명이라고 할 수 있다. React는 이러한 객체를 읽고 DOM을 구성하고 최신으로 유지하는데 이러한 객체를 사용한다.
출처 : https://velog.io/@gyumin_2/React-JSX%EB%9E%80%EC%A0%95%EC%9D%98-%EC%9E%A5%EC%A0%90-%EB%AC%B8%EB%B2%95-%ED%8A%B9%EC%A7%95-%EB%93%B1