JSX 활용

JSX는 JavaScript 표현식(expression) (opens new window)을 중괄호({})로 묶어 데이터를 바인딩(Binding) 한다. 쉽게 말해 HTML 코드에서 데이터를 빼내 변수에 등록한 후, 변수를 HTML 코드에 바인딩(binding)할 수 있다는 말이다.

상태가 변경되면 JSX 요소가 반환되고 반환된 요소를 렌더링 한다.

1. 데이터 바인딩 하기

Data는 곧 상태(State)가 된다. 해당 데이터를 요소 내부에 바인딩 시키는 작업을 해보자

const app = (
  <div className="app">
    <h1 className="app-title">
      <span lang="en"></span>
    </h1>
  </div>
)

위의 app의 요소 내부의 콘텐츠를 분리시키는 작업을 한다.

// Data === State
const state = {
  appClassName: 'app',
  apptitleClassName: 'app-title',
  appHeadlineContents: ['React', '앱'],
}

분리한 데이터를 요소 내부에 바인딩 할 때 아래와 같이 중괄호({}, Curly Brackets)를 사용해서 바인딩 할 수 있다. 이 방식을 사용하면 동적으로 콘텐츠 변경이 가능하다.

const app = (
  <div className={state.appClassName}>
    <h1 className={state.appTitleClassName}>
      <span lang="en">{state.appHeadlineContents[0]}</span>{' '}
      {state.appHeadlineContents[1]}
    </h1>
  </div>
)

1-(1) 결과

import React from 'react'
import ReactDOM from 'react-dom'

// Data === State
const state = {
  appClassName: 'app',
  appTitleClassName: 'app-title',
  appHeadlineContents: ['React', '앱'],
}

const app = (
  <div className={state.appClassName}>
    <h1 className={state.appTitleClassName}>
      <span lang="en">{state.appHeadlineContents[0]}</span>{' '}
      {state.appHeadlineContents[1]}
    </h1>
  </div>
)

ReactDOM.render(app, document.getElementById('root'))

2. 콘텐츠 컴파일

JSX 코드의 {}는 JavaScript 표현식의 연산된 결과 값을 처리하여 콘텐츠를 컴파일 한다. 아래의 데이터를 요소에 바인딩 해보자

const bindingContents = {
  number: 909,
  string: '콘텐츠 바인딩',
  howCanIuseJSexpressionInsideJSX() {
    return 'JavaScript 식(Expression)은 항상 값을 반환함으로 {}안에 바인딩이 가능하다'
  },
}

{}내부에서 + 1 연산자를 사용할 수 있고 템플릿 리터럴을 사용할 수도 있다.

const app = (
  <div className="app">
    {bindingContents.number + 1} {`${bindingContents.string} hi!!`}
  </div>
)

또는 아래와 같은 방식으로도 자바 스크립트 식을 바인딩 할 수 있다.

const app = (
  <div className="app">{bindingContents.howCanIuseJSexpressionInsideJSX()}</div>
)

replace() 메서드를 사용해서 공백을 -기호로 변경할 수 있다.

const app = (
  <div className="app">
    {bindingContents.howCanIuseJSexpressionInsideJSX().replace(/\s/g, ' - ')}
  </div>
)

\s 공백, /g 여러개를 선택

정규표현식 공부하기

단, 식이 아닌 문은 사용이 불가능하다 (오류 발생)

const app = (
  <div className="app">
    {if (true) {'hi'} else {'oops'}}
  </div>
)

2-(1) 결과

import React from 'react'
import ReactDOM from 'react-dom'

const bindingContents = {
  number: 909,
  string: '콘텐츠 바인딩',
  howCanIuseJSexpressionInsideJSX() {
    return 'JavaScript 식(Expression)은 항상 값을 반환함으로 {}안에 바인딩이 가능하다'
  },
}

const app = (
  <div className="app">
    {bindingContents.number + 1} {`${bindingContents.string} hi!!`}
    <div>{bindingContents.howCanIuseJSexpressionInsideJSX()}</div>
  </div>
)

ReactDOM.render(app, document.getElementById('root'))

2.1 정리

2.1-(1) 문자 값

<h1>{`${headline}(${abbrs.jsx})`}</h1>

2.1-(2) 숫자 값

<span>{number % 4}</span>

2.1-(3) 함수 (또는 메서드) 결과 값

<p>{formatCount()}</p>

3. 속성 컴파일

속성 값으로 큰 따옴표("") 대신 중괄호({})로 묶어 JavaScript 표현식을 사용해 동적으로 속성에 데이터를 바인딩할 수 있다.

const app = <abbr title={abbrs.jsx}>{headline}</abbr>

3-(1) 스타일 속성 (인라인)

스타일 코드를 JavaScript 객체({})로 표기하여 사용한다.

const app = <li style={{ color: '#ea6666', fontWeight: 900 }}>스타일 속성(인라인)</li>

3-(2) 스타일 속성 (객체)

스타일 코드를 설정한 객체를 변수에 분리하여 처리할 수도 있다.

const liStyle = { color: '#ea6666', fontWeight: 100 }

const app = <li style={liStyle}>스타일 속성(객체)</li>

3-(3) 클래스 속성

CSS 클래스 속성을 React 요소에 설정하고자 한다면? JavaScript 예약어 class 대신 className을 사용해야 한다.

const app = <li className="bordered rounded">클래스 속성</li>

3-(4) 클래스 속성 (동적 처리)

동적으로 CSS 클래스 이름을 변경해야 할 경우, 아래와 같이 {}를 사용해 처리합니다.

const borderColor = 'blue' / 'red', 'green'  

const app = <li className={`rounded bordered bordered-${borderColor}`}>
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'

const state = {
  appClass: 'app',
}

const borderColor = 'blue'

const liStyle = { color: '#ea6666', fontWeight: 100 }

const app = (
  <div className={state.appClass}>
    <h1 className="a11y-hidden">속성 컴파일</h1>
    <ul>
      {/* 직접 스타일 추가 */}
      <li style={{ color: '#ea6666', fontWeight: 900 }}>스타일 속성(인라인)</li>
      {/* 영역 외부에서 설정한 스타일 추가 */}
      <li style={liStyle}>스타일 속성(객체)</li>
      <li className="bordered rounded">클래스 속성</li>
      <li className={`rounded bordered bordered-${borderColor}`}>
        클래스 속성(동적 처리)
      </li>
    </ul>
  </div>
)

ReactDOM.render(app, document.getElementById('root'))

4. 조건부 렌더링

4-(1) if 문

아래와 같은 조건문을 만들어 요소에 바인딩 할 수 있다. Math.random() 메서드를 사용해서 값이 랜덤으로 나올 수 있도록 추가적으로 설정할 수 있다.

조건문

// 조건부 처리할 함수
function conditionaRendering(usingList = false) {
  // 조건문 if, switch
  if (usingList) {
    return (
      <ul>
        <li>조건 문 사용</li>
        <li>조건 식 (3항식, 논리곱/합 연산자) 활용</li>
      </ul>
    )
  } else {
    return <p>"조건 문 활용" 또는 "조건 식 (3항식, 논리곱/합 연산자) 활용"</p>
  }
}

function randomBoolean() {
  return Math.random() < 0.5 ? true : false
}

데이터 바인딩

이때도 마찬가지로 중괄호({})를 사용해서 값을 넣어준다.

const app = (
  <div className="app">
    <h1>조건부 렌더링</h1>
    {conditionaRendering(randomBoolean())}
  </div>
)

4-(2) switch 문

조건문

// 조건부 처리할 함수
function conditionaRendering(count = 0) {
  // 조건문 switch
  switch (count) {
    case 1:
      return (
        <ul>
          <li>조건 문 사용</li>
          <li>조건 식 (3항식, 논리곱/합 연산자) 활용</li>
        </ul>
      )
      break
    case 2:
      return <p>"조건 문 활용" 또는 "조건 식 (3항식, 논리곱/합 연산자) 활용"</p>
      break
    default:
      return (
        <p>
          React의 <abbr title="JavaScript Syntax eXtension">JSX</abbr>는
          JavaScript 객체(React 요소)를 반환합니다.
        </p>
      )
  }
}

// 숫자를 전달하면 항상 0, 1, 2 중에 하나인 값을 반환하도록 만든다.
function randomCount(number) {
  return number % 3
}

참고

randomCount() 함수에 사용된 나머지 연산자 (%) 가위, 바위, 보 게임을 만들 수 있다.

데이터 바인딩

const app = (
  <div className="app">
    <h1>조건부 렌더링</h1>
    {conditionaRendering(randomCount(Math.floor(100 * Math.random())))}
  </div>
)

4-(3) 3항식

// 목록 또는 단락을 조건부 렌더링 하기 위한 조건 상태
let usingList = true
let usingBorderColor = true

const app = (
  <div className="app">
    <h1>조건부 렌더링</h1>
    {/* JSX 내부의 주석 처리 */}
    {/* 조건에 따라 목록을 렌더링 */}
    {usingList ? (
      <ul>
        <li>조건 문 활용</li>
        <li
          className={`bordered ${
            usingBorderColor ? 'bordered-red' : ''
          }`.trim()}
        >
          조건 식 (3항식, 논리곱/합 연산자) 활용
        </li>
      </ul>
    ) : (
      <p>"조건 문 활용" 또는 "조건 식 (3항식, 논리곱/합 연산자) 활용"</p>
    )}
  </div>
)

4-(4) 논리 연산자

// 목록 또는 단락을 조건부 렌더링 하기 위한 조건 상태
let usingList = true
let usingBorderColor = true

const a11y = {
  hiddenClass: 'a11y-hidden',
}

const app = (
  <div className="app">
    <h1 className={a11y.hiddenClass || null}>조건부 렌더링</h1>
    {/* JSX 내부의 주석 처리 */}
    {/* 조건에 따라 목록을 렌더링 */}
    {usingList ? (
      <ul>
        <li>조건 문 활용</li>
        <li
          className={`bordered ${
            usingBorderColor ? 'bordered-red' : ''
          }`.trim()}
        >
          조건 식 (3항식, 논리곱/합 연산자) 활용
        </li>
      </ul>
    ) : (
      <p>"조건 문 활용" 또는 "조건 식 (3항식, 논리곱/합 연산자) 활용"</p>
    )}
  </div>
)

4.1 코드 정리

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'

// 조건부 처리할 함수
function conditionaRendering(usingList = false) {
  // 조건문 if, switch
  if (usingList) {
    return (
      <ul>
        <li>조건 문 사용</li>
        <li>조건 식 (3항식, 논리곱/합 연산자) 활용</li>
      </ul>
    )
  } else {
    return <p>"조건 문 활용" 또는 "조건 식 (3항식, 논리곱/합 연산자) 활용"</p>
  }
}

function randomBoolean() {
  return Math.random() < 0.5 ? true : false
}

const app = (
  <div className="app">
    <h1>조건부 렌더링</h1>
    {conditionaRendering(randomBoolean())}
  </div>
)

ReactDOM.render(app, document.getElementById('root'))

5. 리스트 렌더링

5-(1) 들어가기 전

리스트를 레더링하여 JSX 요소에 데이터를 바인딩 할 때 아래와 같이 배열 데이터를 순환하여 사용한다.

forEach() 메서드는 왜 사용하지 않는가?

사용을 못하는 것은 아니지만forEach() 메서드는 값을 반환하지 않기 때문에 JSX에서 사용하기에 적합하지 않다.

실습 (1)

아 위에서 먼저 콘솔 패드에서 map() 메서드를 사용해서 배열 데이터를 바인딩 한 것처럼 JSX에서도 아래와 같이 배열 데이터를 요소에 바인딩 했다.

사용 방법은 이전의 데이터 바인딩 방법과 똑 같다. {} 로 묶어주고 그 안에서 map() 메서드를 사용하고 JSX 요소를 작성해서 순환되는 데이터가 어디에 들어가야 할지 설정한다.

const numbers = [500, 50, 5, 0.5]

const app = (
  <div className="app">
    <h1>리스트 렌더링</h1>
    <ul>
      {numbers.map((n) => (
        <li>{n * 2}</li>
      ))}
    </ul>
  </div>
)

⚠️ 오류

React에서는 리스트를 렌더링 할 때, 각 아이템을 구분 할 수 있도록 고유한 key 값을 부여해야한다. 오류를 해결하기 위해 고유한 식별자(id) 값을 설정하자

아래와 같이 indexkey 값으로 해서 각 아이템의 식별자로 만들었다. (오류 해결)

const app = (
  <div className="app">
    <h1>리스트 렌더링</h1>
    <ul>
      {numbers.map((n, i) => (
        <li key={i}>{n * 2}</li>
      ))}
    </ul>
  </div>
)

실습 (2)

실습(1)과 같은 간단한 예제 말고 복잡한 배열 데이터 바인딩 해보자 아래의 강사의 정보를 담고 있는 배열 데이터가 있다.

const FEML_lecturers = [
  {
    id: 'lecturer-az081871',
    name: '김데레사',
    module: 'A',
    facebook: 'http://facebook.com/seulbinim',
    image: 'http://yamoo9.github.io/images/photo-deresa@2x.png',
  },
  {
    id: 'lecturer-az081872',
    name: '야무',
    module: 'B, C',
    facebook: 'http://facebook.com/yamoo9',
    image: 'http://yamoo9.github.io/images/photo-yamoo9@2x.png',
  },
]

5-(2) 데이터 바인딩

const app = (
  <div className="app" role="main" aria-labelledby="main-title">
    <h1 id="main-title">Front-End Masters League 강사진</h1>
    <ul className="lecturers">
      {FEML_lecturers.map((lecturer) => (
        <li className="lecturers" key={lecturer.id}>
          <a href={lecturer.facebook} rel="noreferer nopener">
            <figure className="lecturer-info">
              <img src={lecturer.image} alt="" className="lecturer-photo" />
              <figcaption>
                {lecturer.module} 모듈을 담당 할 {lecturer.name} 강사 Facebook
                바로가기
              </figcaption>
            </figure>
          </a>
        </li>
      ))}
    </ul>
  </div>
)

5.1 리스트 조건부 처리

5.1-(1) 정리

배열 데이터를 순환 처리 해서 사용하도록 map()메서드를 사용하고 각 아이템을 데이터 바인딩을 한다. 그리고 리스트에는 고유한 key를 가지고 있어야만 오류가 표시되지 않는다.

6. 주의할 점

6-(1) 속성 이름은 camelCase 표기법으로 사용하기

JSX는 HTML이 아닌 JavaScript 식이다. 그래서 React DOM은 HTML 표준 속성 이름 중 일부는 그대로 이름을 사용할 수 없다. 예를 들어 classclassName으로, tabindextabIndex로 사용해야 한다. 즉, 음절이 2개 이상인 경우 camelCase로 표기하기!

단, 접근성 속성은 그대로 사용해도 괜찮다.

aria-* 접두사가 붙거나, role과 같은 접근성 관련 속성은 기존에 HTML에서 사용하던 그래도 사용한다.

const app = (
  <div className="app" role="main" aria-labelledby="main-title">
    <h1 id="main-title">Front-End Masters League 강사진</h1>
    </ul>
  </div>

6-(2) 콘텐츠가 없는 요소는 항상 닫아야 한다.

JSX는 XML 문법에 따라 콘텐츠가 없는 빈 요소(empty element)는 반드시 닫아(/>) 줘야 한다. (예: <img/>, <br/>, <area/>, <meta/>, <link/>등)

6-(3) 기본적으로 루트 요소는 하나만 사용한다.

root 요소 <div>위에 root 요소를 하나 더 생성하니 오류가 발생한다.

<div>요소로 감싸줘서 root 요소가 하나만 있을 수 있도록 해야한다. (단, 이 경우는 의미없는 요소를 사용했기 때문에 시멘틱 마크업이라고 할 수 없다.)

또는 <React.Fragment> 요소를 사용해서 랩핑할 수 있다. (단, React를 불러와야 사용할 수 있다.)

const app = (
  <React.Fragment>
    <header>앱 헤더</header>
    <div className="app" role="main" aria-labelledby="main-title">
      <h1 id="main-title">Front-End Masters League 강사진</h1>
      <ul className="lecturers">{**}</ul>
    </div>
  </React.Fragment>
)

<React.Fragment><></>로 작성해줘도 적용된다. <React.Fragment>의 별칭 같은 거라고 생각면 좋다.

const app = (
  <>
    <div className="app"></div>
    <h1>조건부 렌더링</h1>]
  </>
)

Last updated