const element = <h1 className="greeting">Hello, world!</h1>;
위에 희한한 태그 문법은 문자열도, HTML도 아니다. JSX라 하며 JavaScript를 확장한 문법이다. UI가 어떻게 생겨야 하는지 설명하기 위해 React와 함께 사용할 것을 권장한다.
JSX는 React “엘리먼트(element)”를 생성하는 표현식이다.
Babel은 JSX를 React.createElement()
호출로 컴파일한다.
맨 위의 예시 코드는 컴파일을 통해 아래와 같이 컴파일되며 객체를 표현한다.
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
};
이러한 객체를 “React element”라고 하며, 화면에서 보고 싶은 것을 나타내는 표현이라 생각하면 된다.
이제 JavaScript에서 DOM elements를 만들기 위해 document.createElement
했던 것과 달리 React에서는 주로 JSX를 통해 eactDOM.createElement
를 호출해 React elements를 만들게 된다. React elements는 메모리 상에서 존재하다가 ReactDOM을 통해 실제 DOM과 동기화된다.
특정 JSX가 어떻게 JavaScript로 변환되는지 시험해보고 싶다면 아래 링크를 사용해보자.
➡️ Babel · The compiler for next generation JavaScript
위에서 JSX가 무엇인지를 알아봤으니, 리액트에서 JSX를 어떻게 사용할 수 있을지를 알아보자.
import React from 'react';
// JSX는 React.createElement를 호출하는 코드로 컴파일된다. React가 스코프내에 존재해야한다.
import MyButton from 'MyButton';
// 사용자 정의 컴포넌트를 태그로 사용할 때는 해당 컴포넌트가 반드시 스코프내에 존재해야한다.
<MyButton color"blue">Click Me</MyButton>
JSX 태그의 첫 부분은 React element의 타입을 결정한다.
<MyButton>
같은 사용자 정의 컴포넌트<div>
, <span>
같은 내장 컴포넌트어트리뷰트에 따옴표를 이용해 문자열 리터럴을 정의할 수 있다.
const element = <a href="https://www.reactjs.org"> link </a>;
중괄호를 사용하여 어트리뷰트에 JavaScript 표현식을 삽입할 수도 있다.
const element = <img src={user.avatarUrl}></img>;
어트리뷰트에 JavaScript 표현식을 삽입할 때 중괄호 주변에 따옴표를 입력하지 마라. 따옴표(문자열 값에 사용) 또는 중괄호(표현식에 사용) 중 하나만 사용하고, 동일한 어트리뷰트에 두 가지를 동시에 사용하면 안 된다.
JSX는 JavaScript로 바뀌고 JSX로 작성된 속성은 JavaScript 객체의 키가 된다. 자신의 컴포넌트에서 종종 이러한 속성을 변수로 읽어들일 수 있다. 그러나 JavaScript는 변수 이름에 제한이 있다. 예를 들어 변수명에 -
를 포함하거나 class
와 같은 예약어를 사용할 수 없다 .
class는 “HTML Attribute”이고 className은 “DOM Property”이다.
태그가 비어있다면 XML처럼 />
를 이용해 바로 닫아주어야 한다
const element = <img src={user.avatarUrl} />;
JSX 태그는 자식을 포함할 수 있다. 여는 태그와 닫는 태그가 있는 JSX 표현에서 두 태그 사이의 내용은 props.children
이라는 특수한 prop으로 넘겨진다.
<MyComponent>Hello world!</MyComponent>
이 예제에서 props.children
은 "Hello world!"
이다.
JSX의 자식으로 주로 문자열 리터럴, JSX element(?), {}
로 감싼 JavaScript 표현식을 사용한다. 그러나 직접 만든 컴포넌트에 넘겨지는 자식들은 렌더되기 전에 React가 이해할 수 있는 형태로 변환된다면 어떤 것이든 넘겨질 수 있다.
JSX 내에서도 점 표기법을 사용하여 React 컴포넌트를 참조할 수 있다.
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
}
React element 타입에 일반적인 표현식은 사용할 수 없다. 만약 element 타입을 지정할 때 일반적인 표현식을 사용하고자 한다면 대문자로 시작하는 변수에 배정한 후 사용할 수 있다.
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
이러한 방식으로 상황에 따라 PhotoStory
혹은 VideoStory
를 렌더할 수있다.
false
, null
, undefined
와 true
는 유효한 자식이다. 그저 렌더링 되지 않을 뿐이다. 이는 React element들을 조건부 렌더링할 때 유용하다.
<div>
{showHeader && <Header />}
<Content />
</div>
위 예시의 JSX는 showHeader
가 true
일 때 <Header />
를 렌더링한다.
JSX 안에서 prop을 사용하는 방법은 여러 가지가 있다. 아래의 예시와 같이 JavaScript 표현을 {} 안에 넣어서 JSX 안에서 prop으로 사용할 수 있다.
<MyComponent foo={1 + 2 + 3 + 4} />
MyComponent의 props.foo
의 값은 1 + 2 + 3 + 4
의 표현식이 계산되기 때문에 10
이다.
아직 다루지 않았지만, 컴포넌트에서는 JSX를 반환하게 되는데 JSX는 단일 요소로 반환되어야한다.
예를 들어 아래 코드는 반환할 수 없다.
<MyComponent />
<MyButton />
이를 상위 태그로 래핑하거나 빈 태그인 React fragment
를 사용해 래핑할 수 있다.
<>
<MyComponent />
<MyButton />
</>
JSX는 HTML처럼 보이지만 내부적으로는 일반 JavaScript 객체로 변환된다. 함수에서 두 객체를 배열로 래핑하지 않고는 반환할 수 없는 것처럼, 두 개의 JSX 태그를 다른 태그나 조각으로 래핑하지 않고는 반환할 수 없다.
props
를 전달할 수 있다.props.children
로 전달된다.