JSX 이해하기

Nochi·2021년 6월 20일
0

React

목록 보기
1/5
post-thumbnail

해당 내용은 React 공식 홈페이지에서 공부한 내용입니다.
내용이 같다는 점 이해 부탁드립니다.

JSX는 React.createElement 함수를 편리하게 사용해주는 JavaScript + XML 이다.

아래는 JSX 문법을 이용하여 만든 MyButton 함수이다.

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

위의 코드는 아래와 같이 컴파일 된다.

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

React Element의 타입 지정하기

JSX 태그의 첫 부분은 React element의 타입을 결정한다.

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

JSX는 React.createElement를 호출하는 코드로 코드로 컴파일 되기 때문에 React 라이브러리 역시 JSX 코드와 같은 스코프 내에 존재해야만 한다.

아래의 예시를 통해 보면, React와 CusteomButton는 JavaScript 코드에선 직접적으로 사용되진 않지만 JSX 태그로 사용하기 위해 꼭 import 해야한다.

import React from 'react'
import CusteomButton from './CustomButton';

function WarningButton() {
  // return React.createElement(CustomButton, {color:'red'}, null);
  return <CustomButton color="red" />;
}

JavaScript 번들러를 사용하지 않고

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

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

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" />
}

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

Element가 소문자로 시작하는 경우에는 <div>나 <span>같은 내장 컴포넌트라는 것을 뜻하며 'div'나 'span' 같은 문자열 형태로 React.createElement에 전달된다. <Foo />와 같이 대문자로 시작하는 타입들은 React.createElement(Foo)의 형태로 컴파일되며 JavaScript 파일 내에 사용자가 정의했거나 import한 컴포넌트를 가리킨다.

컴포넌트의 이름은 대문자로 시작하는 것을 추천한다.

[예를 들어 아래의 코드는 예상대로 실행되지 않을 것]

import React from 'react';

// [잘못된 사용법] 아래는 컴포넌트이므로 대문자화 해야 한다.
function hello(props) {
  // [올바른 사용법] 아래의 <div> 사용법은 유효한 HTML 태그이기 때문에 유효하다.
  return <div>Hello {props.toWhat}</div>;
}

function HelloWorld() {
  // [잘못된 사용법] React는 <hello />가 대문자가 아니기 때문에 HTML 태그로 인식한다.
  return <hello toWhat="World" />;
}

이를 고치기 위해 hello => Hello로 바꾸고 참조할 때 <Hello />를 사용해야 한다.

import React from 'react';

// [올바른 사용법] 아래는 컴포넌트이므로 대문자로 시작해야 한다.
function Hello(props) {
  // [올바른 사용법] 아래의 <div> 사용법은 유효한 HTML 태그이기 때문에 유효하다.
  return <div>Hello {props.toWhat}</div>;
}

function HelloWorld() {
  // [올바른 사용법] React는 <Hello />가 대문자로 시작하기 때문에 컴포넌트로 인식한다.
  return <Hello toWhat="World" />;
}

실행 중에 타입 선택하기

React element 타입에 일반적인 표현식은 사용할 수 없다. 만약 element 타입을 지정할 떄 일반적인 표현식을 사용하고자 한다면 대문자로 시작하는 변수에 배정한 후 사용할 수 있다.

import React from 'react';
import { PhotoStroy, VideoStroy } from './stroies';

const components = {
  photo: PhotoStroy,
  video: VideoStroy
};

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

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

import React from 'react';
import { PhotoStroy, VideoStroy } from './stroies';

const components = {
  photo: PhotoStroy,
  video: VideoStroy
};

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

JSX 안에서의 prop 사용

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

JavaScript Expressions as Props

아래의 예시와 같이 JS표현을 {} 안에 넣어서 JSX 안에서 prop으로 사용할 수 있다.

<MyComponent foo={1 + 2+ 3 + 4} />

MyComponent의 props.foo의 값은 표현식이 계산되어 10이다.

if 구문과 for 루프는 JS 표현식이 아니기 때문에 JSX 안에서 그대로 사용할 수 없다. 하지만 JSX 밖의 주변 코드에서 사용할 수 있다.

function NumberDescriber(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>;
}

문자열 리터럴

문자열 리터럴은 prop으로 넘겨줄 수 있다. 아래의 두 JSX 표현은 동일한 표현이다.

<MyComponent message="hello world" />

<MyComponent message={"hello world"} />

문자열 리터럴을 넘겨줄 때, 그 값은 HTML 이스케이프 처리가 되지 않는다. 그래서 아래의 두 JSX 표현은 동일한 표현이다.

<MyComponent message="&lt;3" />

<MyComponent message="<3" />

Props의 기본값은 "True"

Prop에 어떤 값도 넘기지 않을 경우, 기본값은 true 이다. 아래의 두 JSX 표현은 동일한 표현이다.

<MyTextBox autocompleate />

<MyTextBox autocompleate={true} />

일반적으로 prop에 대한 값을 전달하지 않는 것을 권장하지 않는다. ES6 object shorthand와 헷갈릴 수 있기 때문이다.

속성 펼치기

props에 해당하는 객체를 이미 가지고 있다면, ... 를 "전개" 연산자로 사용해 전체 객체를 그대로 넘겨줄 수 있다. 아래의 두 컴포넌트는 동일하다

function App1() {
   return <Greeting firstName="Ben" lastName="Hector" />;
}

function App1() {
  const props = {firstName="Ben" lastName="Hector"}
  return <Greeting {...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는 소비되고 DOM의 button element에 넘겨지지 않는다. 다른 모든 prop는 ...other 객체를 통해서 넘겨지며 이 컴포넌트를 유연하게 만들어준다. onClick과 children prop으로 넘겨지는 것을 볼 수 있다.

전개 연산자는 유용하지만 불필요한 prop을 컴포넌트에 넘기거나 유효하지 않은 HTML 속성들을 DOM에 넘기기도 한다. 꼭 필요할 때만 사용하는 것을 권장.


JSX에서 자식 다루기

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

문자열 리터럴

여는 태그와 닫는 태그 사이에 문자열 리터럴을 넣을 수 있고 이 때 props.children은 그 문자열이 된다. 이는 아래의 예시와 같이 많은 HTML 내장 element에 유용하다.

<MyComponent>Hello World!</MyComponent>

이는 유효한 JSX이다. 여기서 MyComponent의 props.children은 "Hello World!"이다. HTML은 이스케이프 처리가 되지 않으며, 일반적으로 아래와 같이 HTML을 쓰는 방식으로 JSX를 쓸 수 있다.

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

JSX는 각 줄의 처음과 끝에 있는 공백, 빈 줄, 태그에 붙어있는 개행을 제거하며 무자열 리터럴 중간에 있는 개행은 한 개의 공백으로 대체한다.

아래의 예시들은 전부 똑같이 렌더링 된다.

<div>Hello World</div>

<div>
  Hello World
</div>

<div>
  Hello 
  World
</div>

<div>

  Hello World
</div>

JSX를 자식으로 사용하기

JSX element를 자식으로 넘겨 줄 수 있다. 이는 중첩된 컴포넌트를 보여줄 때 유용하다.

<MyCotainer>
  <MyFirstComponent>
  </MyFirstComponent>
</MyCotainer>

다양한 타입의 자식들을 섞어서 사용할 수 있다. 그래서 문자열 리터럴 JSX 자식과 함께 사용할 수 있다.

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

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

render() {
  // 리스트 아이템들을 추가적인 엘리먼트로 둘러쌀 필요는 없다.
  return [
    // key 지정 필수
    <li key="A">First item</li>,
    <li key="B">Sceond item</li>,
    <li key="C">Third item</li>,
  ];
}

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

{} 에 감싸서 JS표현식도 자식으로 넘길 수 있다. 아래의 예시들은 동일한 표현이다.

<MyComponent>foo</MyComponent>

<MyComponent>{'foo'}</MyComponent>

이는 임의의 길이를 가진 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>
  );
}

JS 표현식은 다른 타입의 자식과 같이 쓸 수 있다. 이는 문자열 템플릿을 대신해서 종종 유용하다.

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

함수를 자식으로 사용하기

보통 JSX에 삽입된 JavaScript 표현식은 문자열, React element 혹은 이들의 배열로 환산된다. 하지만 props.children은 다른 prop 들과 마찬가지로 React가 렌더링 할 수 있는 데이터의 형태뿐만 아니라 어떤 형태의 데이터도 넘겨질 수 있다.

// 자식 콜백인 numTimes를 호출하여 반복되는 컴포넌트를 생성한다.
function Repeat(props) {
  let items = [];
  for(let i = 0 ; i < props.numTimes; i++) {
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}

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

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

boolean, null, undefined는 무시된다.

false, null, undefined, true는 유효한 자식이다. 그저 렌더링 되지 않을 뿐.
아래 JSX 표현식들은 동일하게 렌더링 된다.

<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

이는 React element들을 조건부 렌더링할 때 유용하다. 아래의 JSX는 showHeader가 true일 때 동일하게 <Header />를 렌더하게 된다.

<div>
  {showHeader && <Header />}
  <Content />
</div>

한 가지 주의해야 할 점은 0과 같은 "falsy " 값들은 React가 렌더링한다는 점이다.

아래의 예시는 props.messages가 빈 배열일 때 예상과는 다르게 0을 출력하게 된다.

<div>
  {props.messages.length &&
    <MessageList messages={props.messages} />
  }
</div>

이를 고치려면 && 앞의 표현식이 언제나 진리의 값이 되도록 해야한다.

<div>
  { props.messages.length > 0 &&
    <MessageList messages={props.messages} />
  }
</div>

반대로 false, true, null 또는 undefined 와 같은 값들을 출력하고 싶다면 먼저 문자열로 전환해야 한다.

<div>
  My JavaScript variable is {String(myVariable)}.
</div>

0개의 댓글