본문 바로가기
javascript/react

JSX - JSX가 무엇인지와 규칙 그리고 간단한 값 넣어보기

by choi-dev 2024. 11. 27.
 

Babel · Babel

The compiler for next generation JavaScript

babeljs.io

앞서 babel이라고 하는 자바스크립트로 변환해주는 도구를 확인해보겠다.

 

(
  <div className="App">
    <header className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h1 className="App-title">Welcome to React</h1>
    </header>
    <p className="App-intro">
      To get started, edit <code>src/App.js</code> and save to reload.
    </p>
  </div>
)

이와 같은 형태의 코드들을 보면 흔히 HTML 같아 보일 수도 있다. 하지만 이건 자바스크립트이다. 

 

import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/*#__PURE__*/_jsxs("div", {
  className: "App",
  children: [/*#__PURE__*/_jsxs("header", {
    className: "App-header",
    children: [/*#__PURE__*/_jsx("img", {
      src: logo,
      className: "App-logo",
      alt: "logo"
    }), /*#__PURE__*/_jsx("h1", {
      className: "App-title",
      children: "Welcome to React"
    })]
  }), /*#__PURE__*/_jsxs("p", {
    className: "App-intro",
    children: ["To get started, edit ", /*#__PURE__*/_jsx("code", {
      children: "src/App.js"
    }), " and save to reload."]
  })]
});

위에서 자바스크립트라고 하던 녀석을 변환해서 보면 다음과 같은 형태로 나타나는 것을 볼 수 있다. 리액트에서는 컴포넌트라고 하는 것을 사용해 웹 애플리케이션 단에 사용하는 유저 인터페이스를 재사용 가능하도록 도와주어 프로젝트의 유지보수성을 유의미하게 도와주는데 위와 같은 형태로 컴포넌트를 만든다고 하면 정말 끔찍하다.

 

그렇기에 가장 처음에 보았던 HTML과 비슷하게 생긴 문법으로 작성을 하게 되면 리액트에서는 이를 자바스크립트로 형태로 변환시켜주게 된다. 이를 JSX 문법이라고 하고 규칙에 맞춰서 작성해주면 되겠다. 프로젝트를 직접 생성하지는 않고 현재는 찍어 먹어보는 수준이기 때문에 CodeSandBox라고 하는 간단한 툴을 이용해보겠다. 참고로 벨로퍼트의 강의를 따라가고 있다.

 

시작해보기

import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div>
        <h1>리액트를 처음 공부하는 백엔드</h1>
      </div>
    );
  }
}

컴포넌트는 만들어지는 방식이 두 가지가 있다고 하는데 하나는 클래스로, 다른 방법은 함수를 통하여 만드는 방식이 있다고 한다. 일단은 클래스로 만들어지는 방식부터 알아보기로 한다. 클래스로 만드는 컴포넌트의 경우에는 반드시 render 함수가 있어야 한다. 그리고 내부에는 JSX을 리턴해주어야 한다.

 

JSX 문법에 대한 규칙을 지켜주어야 하는데 이를 알아보자.

 

태그를 닫아주어야 한다.

class App extends Component {
  render() {
    return (
      <div>
        <h1>리액트를 처음 공부하는 백엔드</h1>
      
    );
  }
}

이렇게 태그를 닫아주지 않는다면 다음과 같은 에러를 발생시킨다.

 

Cannot assign to read only property 'message' of object 'SyntaxError: /src/App.js: Unterminated JSX contents.

그렇기에 반드시 닫아주어야 하겠다.

 

class App extends Component {
  render() {
    return (
      <div>
        <h1>리액트를 처음 공부하는 백엔드</h1>
        <input type="text" placeholder="this is input text" >
      </div>
    );
  }
}

참고로 간혹 input 태그를 닫지 않는 경우가 있는데 이 또한 에러를 유발시킨다. 이를 유의하자.

 

반드시 하나의 엘리먼트로 감싼다.

class App extends Component {
  render() {
    return (
      <div>
        <h1>리액트를 처음 공부하는 백엔드</h1>
        <input type="text" placeholder="this is input text" />
      </div>
      <div>
        <h1>리액트를 두번째 공부하는 백엔드</h1>
      </div>
    );
  }
}

JSX 내에서 이렇게 입력하면 에러가 발생한다.

 

Cannot assign to read only property 'message' of object 'SyntaxError: /src/App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

JSX에서는 반드시 하나의 엘리먼트로 감싸주어야 하는 규칙이 존재하기 때문에 감싸주어야 한다. 에러 메시지에서는 무언가 잊은 것 같다고 힌트를 알려준 것 같은데 이대로 적용해보자.

 

class App extends Component {
  render() {
    return (
      <>
        <div>
          <h1>리액트를 처음 공부하는 백엔드</h1>
          <input type="text" placeholder="this is input text" />
        </div>
        <div>
          <h1>리액트를 두번째 공부하는 백엔드</h1>
        </div>
      </>
    );
  }
}

음... 일단 오류는 안나는데 이게 뭐지? 하고 좀 찾아보니 Fragment라고 하는 개념이었다. 근데 좀 이해 안간 것은 Fragment라고 명시해주지 않았는데도 잘 되길래 찾아보니까 리액트 16.2 버전 이상에서는 자동으로 React.Fragment의 축약형이라 인지하고 매핑된다고 한다.

 

class App extends Component {
  render() {
    return (
      <div>
        <div>
          <h1>리액트를 처음 공부하는 백엔드</h1>
          <input type="text" placeholder="this is input text" />
        </div>
        <div>
          <h1>리액트를 두번째 공부하는 백엔드</h1>
        </div>
      </div>
    );
  }
}

Fragment를 사용하지 않아도 div로 묶어서 나타낼 수는 있고 이는 에러를 발생시키지는 않는다.

 

다만 개발자 도구로 Document를 찍어보았을 때, 불필요한 div 태그가 늘어난 것을 확인할 수 있다. 따라서 불필요하게 div 태그를 사용하지 않기 위해서는 Fragment를 사용하는 것이 좋을 것으로 보인다.

 

import React, { Component, Fragment } from 'react';

class App extends Component {
  render() {
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드</h1>
          <input type="text" placeholder="this is input text" />
        </div>
        <div>
          <h1>리액트를 두번째 공부하는 백엔드</h1>
        </div>
      </Fragment>
    );
  }
}

불필요한 태그의 남발을 줄이는 것으로는 적합하다.

 

JSX 내에 자바스크립트 값 사용하기

class App extends Component {
  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
        </div>
      </Fragment>
    );
  }
}

이런 식으로 값을 주입해서 넣어볼 수도 있다. 근데 JSX 내에서는 조건부 렌더링을 사용하고 싶을 때는 자바스크립트 if 문을 사용할 수가 없다. 삼항연산자 또는 AND 연산자를 사용하면 조건부로써 렌더링을 동작시킬 수 있다.

 

class App extends Component {
  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
          <div>{name === 'csd' ? <div>'맞음'</div> : <div>'틀림'</div>}</div>
        </div>
      </Fragment>
    );
  }
}

이렇게 동작시켜보면

 

이렇게 나오게 된다.

 

class App extends Component {
  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
          <div>{name === 'csd' && <div>'맞음'</div>}</div>
        </div>
      </Fragment>
    );
  }
}

이런 식으로도 가능하다.

 

class App extends Component {
  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
          {function () {
            if (name === 'c') return <div>'한 글자'</div>;
            if (name === 'cs') return <div>'두 글자</div>;
            if (name === 'csd') return <div>'맞음'</div>;
          }}
        </div>
      </Fragment>
    );
  }
}

실질적으로는 JSX 내에서 복잡한 연산이 들어갈 시에는 별도의 메소드로 분리하여 호출해서 사용한다고 하지만 JSX 내에서 선언이 불가능한 것은 아니다. 위의 코드처럼 해당 함수를 익명 함수로 사용해 실행될 수 있도록 만들면 된다.

 

근데 이게 아무것도 보여지지 않는다. 단순히 위의 코드에서는 함수를 선언만 했을 뿐 사용하지 않아서이기 때문이다.

 

class App extends Component {
  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
          {(function () {
            if (name === 'c') return <div>'한 글자'</div>;
            if (name === 'cs') return <div>'두 글자</div>;
            if (name === 'csd') return <div>'맞음'</div>;
          })()}
        </div>
      </Fragment>
    );
  }
}

함수를 한 번 더 실행해주어야 리액트에 결과값을 나타낼 수 있다.

 

class App extends Component {
  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
          {(() => {
            if (name === 'c') return <div>'한 글자'</div>;
            if (name === 'cs') return <div>'두 글자</div>;
            if (name === 'csd') return <div>'맞음'</div>;
          })()}
        </div>
      </Fragment>
    );
  }
}

이렇게 화살표 함수로 나타낼 수도 있다.

 

class App extends Component {
  sayResult(name) {
    if (name === 'c') return <div>'한 글자'</div>;
    if (name === 'cs') return <div>'두 글자'</div>;
    if (name === 'csd') return <div>'맞음'</div>;
  }

  render() {
    const name = 'csd';
    return (
      <Fragment>
        <div>
          <h1>리액트를 처음 공부하는 백엔드 : {name}</h1>
          <div>{this.sayResult(name)}</div>
        </div>
      </Fragment>
    );
  }
}

아예 외부에서 별도의 함수로 분리하여 사용할 수도 있다.

'javascript > react' 카테고리의 다른 글

state  (0) 2024.12.08
props  (0) 2024.12.05
JSX - style과 주석  (0) 2024.12.05
DOM  (0) 2024.11.27