akjfal

JSX 이해하기 본문

(구)React 공식문서/고급 안내서

JSX 이해하기

akjfal 2023. 2. 17. 11:44

JSX 이해하기

JSX는 React.createElement(component, props, …children) 함수에 대한 문법적 설탕을 제공합니다.

<MyButton color='blue' shadowSize={2}>
	Click
<MyButton>

는 아래와 같이 컴파일됩니다.

React.createElement(MyButton, {color: 'blue', shadowSize: 2}, 'Click')

React Element의 타입 지정하기

JSX 태그의 첫 부분은 React Element의 타입을 결정합니다. 대문자로 시작하는 JSX 태그는 스코프 내에 존재하는 변수를 참조합니다.

React가 스코프 내에 존재해야합니다.

JSX 코드와 같은 스코프 내에 존재해야 해서 다른 파일에 존재한다면 꼭 import 해야 합니다. 단 JavaScript 번들러가 아니라 <script> 태그를 통해 React를 불러왔다면 React는 전역변수로 존재하기 때문에 별도로 불러올 필요가 없습니다.

JSX 타입을 위한 점 표기법 사용

JSX 내에서도 점 표기법을 사용하여 React 컴포넌트를 참조할 수 있습니다. 하나의 모듈에서 여러 React 컴포넌트들을 export 하는 경우에 편리하게 사용할 수 있습니다.

import React from 'react';

const MyComponents = {
	DatePicker: function DatePicker(props) {
		return <div>Imagine a {props.color} datepciker here.</div>
	}
}

function BlueDatePicker() {
	return <MyComponents.DatePicker color='blue'/>

사용자 정의 컴포넌트는 반드시 대문자로 시작해야합니다.

Element가 소문자로 시작하는 경우에는 <div>나 <span> 같은 내장 컴포넌트이고, ‘div’나 ‘span’ 같은 문자열 형태로 React.createElement에 전달됩니다. <Foo />와 같이 대문자로 시작하는 타입들은 React.createElement(Foo)의 형태로 컴파일되며 javascript 파일 내에 사용자가 정의했거나 import 한 컴포넌트를 가리킵니다.

컴포넌트의 이름은 대문자로 하는 것을 추천합니다. 소문자로 사용해야 한다면, 대문자로 시작하는 변수에 할당한 뒤 JSX에서 이 변수를 사용해야 합니다.

실행 중에 타입 선택하기

React Element 타입에 일반적인 표현식은 사용할 수 없습니다. Element타입을 지정할 때 일반적인 표현식을 사용하고자 한다면 대문자로 시작하는 변수에 배정한 후 사용할 수 있습니다. 예를 들어 prop에 따라 컴포넌트를 Render해야하는 경우들이 종종 있습니다.

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
	photo: PhtoStory,
	video: VideoStory
}

function Story(props) {
	// 잘못된 사용법입니다. JSX 타입은 표현식으로 사용할 수 없습니다.
	return <components[props.storyType] story={props.story} />
}

이를 고치기 위해 우선 타입을 대문자로 시작하는 변수에 지정합니다.

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
	photo: PhotoStory,
	vidoe: VideoStory
};

function Story(props){
	// 올바른 사용법입니다. 대문자로 시작하는 변수는 JSX 타입으로 사용할 수 있습니다.
	const SpecificStory = components[props.storyType];
	return <SpecificStory story={props.story} />;
}

JSX 안에서의 prop 사용

JSX 안에서 prop을 사용하는 방법은 여러 가지가 있습니다.

Javascript Expressions as Props

Javascript 표현을 {} 안에 넣어서 JSX 안에서 prop으로 사용할 수 있습니다. 단 if구문과 for루프는 Javascript 표현식이 아니기 때문에 jsx안에서 그대로 사용할 수없지만 다음과 같이 JSX 밖의 주변 코드에서 사용할 수 있습니다.

function NumberDexcriber(props) {
	let description;
	if(props.number % 2 == 0) {
		description = <strong>even</strong>
	} else {
		description = <i>odd</i>;
	}
	return <div>{props.number} is an {description} number>/div>;
}

문자열 리터럴

문자열 리터럴은 props로 넘겨줄 수 있지만 HTML 이스케이프 처리가 되지 않습니다.

// <3
<MyComponent message="&lt;3" />
// <3
<MyComponent message={'<3'} />
// &lt;3
<MyCompnent message={"&lt;3"} />
// <3
<MyCompnent message="<3" />

props의 기본값은 True

props의 기본값은 true입니다. 일반적으로 props에 대한 값을 전달하는 것을 권장하는데 ES6 object shorthand 와 헷갈릴 수 있기 때문입니다.

// ES6 object shorthand
const a = 'a';
{ a }
 => {a: 'a'}

속성 펼치기

props에 해당하는 객체를 이미 가지고 있다면 …를 전개 연산자로 사용해 전체 객체를 그대로 넘겨줄 수 있습니다. 또한 이때 사용하게 될 특정 prop을 선택하고 나머지 prop을 전개 연산자를 통해 넘길 수 있습니다.

const Button = props => {
	const {kind, ...other} = props;
	const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
	return <button className={className} {...other}{ />;
}

const App = () => {
	return (
		<div>
			<Button kind="primary" onClick={() => console.log("clicked!")}>
				Hello World!
				</Button>
		</div>
	)
};

위의 예시에서 kind의 경우 먼저 정의가 되고 나머지는 prop을 통해서 넘어가게 됩니다. 전개 연산자는 불필요하거나 유효하지 않은 HTML 속성들을 DOM에 넘기기도 합니다.

JSX에서 자식 다루기

여는 태그와 닫는 태그가 있는 JSX 표현에서 두 태그 사이의 내용은 props.children이라는 특수한 prop으로 넘겨집니다. 자식을 넘기는 방법에는 여러 가지 방법이 있습니다.

문자열 리터럴

여는 태그와 닫는 태그 사이에 문자열 리터럴을 넣을 수 있고 이때 props.children은 그 문자열이 됩니다. 또한 HTML은 이스케이프 처리가 되지 않으며, 일반적으로 아래와 같이 HTML 쓰는 방식으로 JSX를 쓸 수 있습니다.

<div>this is valid HTML &amp; JSX at the same time.</div>
// this is valid HTML & JSX at the same time

JSX는 각 줄의 처음과 끝에 있는 공백과 빈 줄을 제거합니다. 태그에 붙어있는 개행도 제거되며 문자열 리터럴 중간에 있는 개행은 한 개의 공백으로 대체됩니다. 이러한 방식에 따라 아래의 예시들은 전부 똑같이 렌더링 됩니다.

<div>Hello World</div>

<div>
	Hello World
</div>

<div>
	Hello
	World
</div>

<div>

	Hello World
</div>

JSX를 자식으로 사용하기

JSX Element를 자식으로 넘기면서 다양한 타입의 자식을 섞을 수도 있는데 중첩된 컴포넌트를 보여줄 때 유용합니다. 그래서 문자열 리터럴은 jsx자식과 함께 사용할 수 있습니다. 이는 JSX를 html과 같은 방식으로 작동되는 점 중 하나입니다.

<div>
	Here is a list:
	<ul>
		<li>item 1</li>
	</ul>
</div>

React 컴포넌트는 Element로 이루어진 배열을 반환할 수 있습니다.

render() {
	// 리스트 아이템들을 추가적인 엘리먼트로 둘러쌀 필요 없습니다!
	return [
		<li key="A">First item</li>,
		<li key="B">Second item<li>
	];
}

Javascript 표현식을 자식으로 사용하기

{}에 감싸서 Javascript 표현식도 자식으로 넘길 수 있습니다. 이러한 방식은 임의의 길이를 가진 JSX 표현식의 배열을 렌더링할 때 유용하게 사용됩니다. 아래의 예시는 HTML 배열로 랜더됩니다.

function Item(props){
	return <li>{props.message}</li>
}

function TodoList() {
	const todos = ['finish doc', 'submit pr', 'nag dan to review'];
	return (
		<ul>
			{todos.map((message) => <Item key={message} message={message} />)}
		</ul>
	)
}

Javascript 표현식은 다른 타입의 자식과 같이 쓸 수 있는데 문자열 탬플릿을 대신해서 사용하기도 합니다.

function Hello(props){
	return <div>Hello {props.addressee}!</div>
}

함수를 자식으로 사용하기

보통 JSX에 삽입된 Javascript 표현식은 문자열, React Element, 배열로 환산됩니다. 하지만 props.children은 다른 prop들과 마찬가지로 React가 렌더링할 수 있는 데이터의 형태도 가능하고, 다른 형태의 데이터도 넘겨질 수 있습니다. 또한 예시처럼 직접 만든 컴포넌트가 있다면 props.children을 통해서 콜백을 넘겨받을 수 있습니다.

function Repeat(props){
	let itrems = [];
	for(let i = 0; i < props.numTimes; i++){
		items.push(props.children(i));
	}
	return <div>{items}</div>;
}

function ListOfTenThings(){
	return (
		<Repeat numTimes={10}>
			{(index) => <div key={index}>This is item {index} in the list</div>}
		<Repeat>
	);
}

직접 만든 컴포넌트에 넘겨지는 자식들은 렌더되기 전에 React가 이해할 수 있는 형태로 변환된다면 어떤 것이든 넘겨질 수 있습니다. 일반적이진 않지만, JSX의 기능이 확장성을 확인하고 싶다면 사용할 수 있습니다.

boolean, null, undefined는 무시됩니다.

false, null, undefined와 true는 유효한 자식이며, 렌더링에서는 제외됩니다. 조건부 렌더링에서 유용하지만, 0과 같이 falsy값들은 React가 렌더링을 진행합니다.

<div>{0 && <MyComponent></div>
// 0 이 출력됨

이를 방지하기 위해서는 && 앞을 boolean값이 되도록 해야합니다. 또한 false, true, null, undefined값들을 출력하고 싶다면 문자열로 전환해야 합니다.

'(구)React 공식문서 > 고급 안내서' 카테고리의 다른 글

Portal  (0) 2023.02.22
성능 최적화  (0) 2023.02.20
다른 라이브러리와 통합하기  (0) 2023.02.16
고차 컴포넌트  (0) 2023.02.16
Fragment  (0) 2023.02.16
Comments