JSX

nasagong·2023년 1월 26일
0

React

목록 보기
3/15
post-thumbnail

📚 들어가며

리액트 컴포넌트에서 사용하는 문법인 JSX에 대해 알아보며 컴포넌트를 비롯한 리액트의 전반적인 부분을 알아보도록 하자.


리액트 프로젝트를 생성하고 개발 서버에 접속하는 것 까지 성공했다. 이제 생성된 코드들을 보며 리액트와 친해져보자.

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload !
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

create-react-app을 통해 만들어진 파일 중 하나인 src/App.js다. html로 추정되는 코드들을 읽어보니 나를 처음 맞이해준 리액트 페이지를 구성하는 코드로 추정된다.
첫줄부터 차근차근 읽어보자.

1. import

파이썬에서나 보던 import가 보인다. css파일과 리액트 로고 파일을 가져오고 있는 것 같다. 바닐라 자바스크립트 모듈 파트에서 import를 얼핏 본 적이 있기에 낯설진 않지만, 원래 브라우저에는 모듈을 불러오는 기능이 없었다고 한다. (2017년부터 자바스크립트에도 import가 생겼지만 이건 다른 자바스크립트 파일을 끌어오는 것에 불과하다.)

그렇다면 브라우저는 어떻게 모듈을 불러오고 있는 걸까. 바로 번들러(bundler)라는 기능을 통해서다. 번들러는 쉽게 말해 여러개의 파일을 묶어서 연결해주는 역할을 하는데, 여기저기 분산돼있는 모듈들을 합쳐 하나의 파일로 만들어주는 역할을 한다. 프로젝트 규모가 커질 때 모듈간의 의존성 등을 고려할 필요 없이 스스로 다 처리해준다고 하니 얼마나 편리한 기능인가.. 뿐만 아니라 웹팩에는 바벨이라는 도구가 포함되어 있어 최신 자바스크립트 문법을 ES5 문법으로 변환해준다고 한다. (구 브라우저와의 호환을 위해)

번들러에는 여러 종류가 있지만 리액트 프로젝트에선 주로 webpack을 사용한다고 한다. 웹팩의 설정 같은 부분은 create-react-app이 전부 대신 해줬기 때문에 추가적인 세팅이 필요하지 않은 지금은 여기까지만 알아보도록 하자.

2. JSX

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload !
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

import 아래로는 자바스크립트 함수가 보인다. 이 함수는 컴포넌트라고 불린다. 리액트 프로젝트를 구성하는 최소 단위라고 하는데, 일단은 나중에 더 자세히 알아보도록 하자.

위 컴포넌트는 함수로 이루어져 있으며, div로 감싸진 HTML 코드를 반환하고 있다. 그런데 이 코드가 사실은 HTML이 아니라고 한다. 이런 코드를 바로 자바스크립트의 확장 문법인 JSX라고 부른다.

JSX가 브라우저에서 실행되는 과정

function App(){
  return(
    <div>
      Hello <b>react</b>
    </div>
  );
}

/*  아래는 바벨로 변환된 JSX to JS 코드다 */

function App(){
  return React.createElement("div",null,"Hello ",React.createElement("b",null,"reac"))''
}

JSX는 브라우저에서 실행되기 전 번들링되는 과정에서 앞서 언급한 바벨을 통해 평범한 자바스크립트 코드로 변환된다.
위는 JSX를 JS로 변화하는 예시 코드다.

얼핏 봐도 JSX쪽이 더 직관적이고 작성하기 편리해보인다 !
물론 JSX는 공식적인 자바스크립트 문법은 아니다. 바벨을 통해 자바스크립트로 변환 가능한, 임의로 만든 문법일 뿐이다.

3. JSX 문법

1) 컴포넌트의 요소들은 반드시 하나의 부모로 묶여있어야 한다.

// 1
function App(){
  return(
      <h1>TESTING</h1>
      <h2>NOW</h2>
  );
}

// 2
function App(){
  return(
      <h1>TESTING</h1>
  );
}

코드 1은 제대로 실행되지 않지만 코드 2는 정상적으로 표시된다. 2는 요소가 하나기에 스스로가 곧 <h1></h1>로 감싸진 부모요소다. 반면 1은 두개의 요소가 부모요소 없이 흩어져있다.

function App(){
  return(
    <div>
      <h1>TESTING</h1>
      <h2>NOW</h2>
   </div>
  );
}

div로 감싸니 정상적으로 페이지가 렌더링됐다. 굳이 div가 아닌 빈 태그나 <Fragment>로 감싸줘도 정상적으로 실행된다.(Fragment는 빈 태그와 유사하지만 사용하기 위해선 따로 import해야한다.)

왜 부모요소로 감싸지 않으면 제대로 컴파일되지 않을까?
아직 자세히는 알 수 없지만, Virtual DOM 이 컴포넌트 변화를 감지할 때 효율적으로 비교하기 위해 컴포넌트 내부의 요소들은 하나의 트리로 묶여야 하는 게 원칙이라고 한다.

2. JS 표현

import {Fragment} from 'react'

function App(){
  const name = "nasagong"
  return(
    <Fragment>
      <h1>{name}</h1>
    </Fragment>
  );
}
export default App;

JSX내부에서 자바스크립트 표현식을 사용할 수 있다. 위 코드를 렌더링해보면 정상적으로 nasagong이 출력된다. 매우 편리해보인다.

3. 조건부 연산자

JSX내부에선 if문을 사용할 수 없다. JSX에 진입하기 전 컴포넌트 내에서 if문을 활용해 정리된 값을 JSX에서 사용하는 건 가능하겠으나 자바스크립트 if문 자체를 사용하는 건 불가하다. 대신 굉장히 익숙한 친구인 삼항연산자를 사용한다.
예시를 통해 이해해보자.

function App(){
  const name = "nasagong"
  return(
    <div>
      {name === "nasagong"?
      (<h1>나사공입니다</h1>):
      (<h1>나사공이 아닙니다.</h1>)
      }
    </div> // 삼항연산자 역시 다른 요소로 감싸야 한다
  );
}
export default App;

중괄호로 감싼 후 삼항연산자를 통해 '나사공입니다'를 렌더링하고 있다. 어려울 게 없다. 삼항연산자엔 자바스크립트에서 사용되던 논리연산자를 통한 연산 생략 개념을 사용할 수도 있다. 하나하나 설명할 부분은 아니기에 다양한 예시 코드들과 주석을 보며 이해해보자.

// 1. And 연산자를 통한 연사 생략
function App(){
  const name = "react";
  return(
    <div>
      {name === "react" && <h1>리액트입니다.</h1>}
    </div>
  );
}
export default App;
// name이 "react"일 때 null을 표시하는 코드를 따로 작성하지 않아도 된다.

// 2. false일 때 지정해둔 값을 렌더링하기.
function App(){
  const name = undefined;
  return(
    <div>
      {name || <h1>falsy!</h1>}
    </div>
  );
}
export default App;

크게 어려운 내용은 아니다. 다만 undefined를 다룰 땐 주의하도록 하자. undefined 자체를 렌더링 하게 되면(순화과정 없이 바로 undefined를 리턴해버리면) 렌더링 과정에서 오류가 발생한다. undefined값을 렌더링하고 싶다면 JSX내부에서 하도록 하자. 내부에서 하라는 건 아래 코드처럼 하라는 얘기다.

// 1. JSX 내부에서 undefined를 렌더링

function App(){
  const name = undefined;
  return(
    <div>{name}가 렌더링되었습니다.</div>
  );
}
export default App;

가급적 OR연산자를 사용해 undefined만 렌더링되는 상황은 피하도록 코드를 작성하자.

4. 인라인 스타일링

리액트를 사용해 DOM요소에 스타일을 적용할 수 있다. 하지만 기존에 알던 방식과는 다소 차이가 있다.

  • 문자열 형태가 아닌 객체를 통해 반영한다.
  • 스타일 이름은 하이픈 대신 카멜 표기법을 사용한다.

코드를 통해 빠르게 확인해보자.

function App(){
  const name = '리액트';
  const style = {
    backgroundColor:'black',
    color:'aqua',
    fontSize:'48px',
    fontWeight:'bold',
    padding:16 // 단위 생략시 자동으로 px가 지정된다. 
  };
  return <div style={style}>{name}</div>;
}

export default App;

브라우저에 리액트가 예쁘게 출력된다. 객체를 통해 스타일을 적용한다는 게 좀 재밌는 것 같다..
이번엔 css를 사용해 스타일을 지정할 때의 주의점을 확인해보자.

class 대신 className 사용하기

HTML과 마찬가지로 리액트의 DOM요소에도 클래스를 지정해 css의 스타일을 적용할 수 있다. 다만 class 대신 className을 사용할 뿐이다. 미리 작성해 둔 css파일을 리액트 앱에 적용시켜보자.

import './App.css';

function App(){
  const name = '리액트';
  return <div className="react">{name}</div>;
}
export default App;

역시나 잘 적용된다. 클래스를 쉽게 지정할 수 있으니 굉장히 편리하게 스타일을 적용할 수 있을 것 같다. 무려 자바스크립트 코드에서... 그냥 JS로 클래스를 지정하려고 했으면 굉장히 더러운 코드가 나왔을 거다.

5. 자잘한 문법 요소들

꼭 닫아야 하는 태그

<form>
  이름:<br>
  <input>
</form>

HTML에서 input과 같은 태그들은 굳이 닫지 않아도 된다고 배웠다. JSX에서 그러면 안 된다고 한다..ㅜ DOM 트리의 완결성(?)에 민감한 문법이라 그런 것 같다. 코드를 보자.

function App() {
  return (
    <div>
      <h1>입력창 나와라!</h1>
      <input>
    </div>
  );
}
export default App;

//이렇게 써보는 건 어떨까?
function App() {
  return (
    <div>
      <h1>입력창 나와라!</h1>
      <input/>
    </div>
  );
}
export default App;

input창을 닫아주지 않았더니 오류가 발생했다... 어차피 에디터에서 알아서 닫아주긴 두번째 코드처럼 작성하면 굳이 태그를 두개 쓰지 않아도 열면서 동시에 닫을 수 있다고 한다. 이를 self-closing이라고 부른다.

주석

function App() {
  //나는 좋은 개발자니까 주석을 써봐야겠다
  return (
    <div>
      <h1>텍스트 나와라!!</h1>
      // 나왔나?
      {/* 나왔겠지? */}
    </div>
  );
}
export default App;

JSX내부에서 평소 쓰던 것처럼 주석을 달아버리면

주석도 같이 렌더링 돼버린다. JSX 내부에선 {/* */} 형태로 적어주자.

profile
잘쫌해

0개의 댓글