Front-End

리액트의 첫 시작 / JSX 본문

리액트

리액트의 첫 시작 / JSX

jeongsso 2023. 2. 17. 16:09

1.   JSX

시작 전에 코드 먼저 이해해 보고 가자.

리액트를 처음하게 되면 코드가 낯설 수 있는데, 하나씩 이해해 보자.

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

여기 import 구문이 사용되었는데, 이는 특정 파일을 불러오는 것을 의미합니다.

리액트로 만든 프로젝트의 자바스크립트 파일에서는 import를 사용하여 다른 파일들을 불러와 사용할 수 있다.

이렇게 모듈을 불러와서 사용하는 것은 사실 원래 브라우저에는 없던 기능입니다.

브라우저가 아닌 환경에서 자바스크립트를 실행할 수 있게 해 주는 환경인 Node.js에는 지원하는 기능입니다.

 

이러한 기능을 브라우저에서도 사용하기 위해 번들러를 사용합니다.

번들은 묶는다는 뜻입니다. 즉, 파일을 묶듯이 연결하는 것입니다.

 

 

번들러 도구를 사용하면 import로 모듈을 불러왔을 때 불러온 모듈을 모두 합쳐서 하나의 파일을 생성해 줍니다.

또 최적화 과정에서 여러 개의 파일로 분리될 수도 있습니다.

 

2017년부터는 브라우저에서도 import 구문을 사용할 수 있게 되었지만, 

이는 단순히 다른 경로에 있는 자바스크립트를 불러오는 용도로만 사용되기 때문에 프로젝트 번들링과는 다릅니다.

 

웹팩을 사용하면 SVG 파일과 CSS파일도 불러와서 사용할 수 있습니다.

이렇게 파일들을 불러오는 것은 웹팩의 로더(loader)라는 기능이 담당한다.

로더는 여러 가지 종류가 있는데 

css-loader는 CSS파일을 불러올 수 있게 하고,

file-loader는 웹 폰트나 미디어 파일 등을 불러올 수 있게 하고,

babel-loader는 자바스크립트 파일들을 불러오면서 최신 자바스크립트 문법으로 작성된 코드를

바벨이라는 도구를 사용하여 ES5 문법으로 변환해 줍니다.

 

 

왜 바꾸는가 ??

 

ES5는 이전 버전의 자바스크립트를 의미하는데, 최신 자바스크립트 문법을 ES5 형태로 변경하는 이유는

구버전 웹 브라우저와 호환하기 위해서입니다.

앞으로 배우게 될 JSX 문법도 자바스크립트 정식 문법이 아니므로 ES5 형태의 코드로 변환해야 합니다.

 


 

웹팩의 로더는 원래 직접 설치하고 설정해야 하지만 리액트 프로젝트를 만들 때 사용하는

create-react-app이 번거로운 작업을 모두 대신해 주기 때문에 우리는 별도의 설정을 할 필요는 없습니다

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

이 코드는 App이라는 컴포넌트를 만들어줍니다.

function 키워드를 사용하여 컴포넌트를 만들었는데, 이러한 컴포넌트를 함수 컴포넌트라 합니다.

프로젝트에서 컴포넌트를 렌더링 하면 함수에서 반환하고 있는 내용을 나타냅니다.

(렌터링 "보여준다"는 의미)

마치 HTML 같지만, HTML은 아닙니다.

그렇다고 문자열 템플릿도 아니고,

이건 JSX 라고 부릅니다!

 

 

 


2.   JSX란?

JSX는 자바스크립트의 확장 문법이며 XML과 매우 비슷하게 생겼습니다.

브라우저에서 실행되기 전에 코드가 번들링되는 과정에서 바벨을 사용하여 일반 자바스크립트 형태의 코드로 변환된다.

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

위 JSX코드가 아래 코드로 변환됩니다.

function App() {
  return React.createElement("div", null, "Hello", React.createElement("b", null, "react"));

만약 컴포넌트가 렌더링 할 때마다 JSX 코드를 작성하는 게 아니고

위 코드처럼 매번 React.createElement 함수를 사용한다면 귀찮을 것이다.

 

JSX를 사용하면 매우 편하게 UI를 렌더링 할 수 있습니다.

⭐ UI (User Interface) : 사용자가 제품이나 서비스를 마주할 때 보고 조작하는 모든 화면

⭐ UX (User Experience) : UI를 익숙하게 사용할 수 있게하는 경험적인 요소                  

 

 

 

 

 


3.   JSX의 장점

(1)  보기 쉽고 익숙하다 !

몇 초만 보아도 JSX를 사용하는 편이 더 가독성이 높고 작성하기 쉽습니다.

결국 HTML 코드 작성과 비슷하기 때문입니다.

자바스크립트 요소들을 일일이 만들어서 사용하면 불편할텐데,

HTML과 비슷해서 간편하여 JSX를 사용하는 주된 이유가 됩니다!

 

 

(2)  더욱 높은 활용도 !

JSX에서는 우리가 알고 있는 div나 span같은 HTML 태그를 사용할 수 있을 뿐만 아니라,

앞으로 만들 컴포넌트로 JSX 안에서 작성할 수 있다.

 

App.js 에서는 App 컴포넌트가 만들어졌는데

scr/index.js 파일을 열어 보면 이 App 컴포넌트를 마치 HTML 태그 쓰듯이 그냥 작성합니다.

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.creacteRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>
);

// If you want to start measuring perfomance in your app, pass a function
// to log results ( for example : reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more : http://bit.ly/CRA-vitals
reportWebBitals();

위 코드에서 document.getElementById를 사용하여 id가 root인 HTML 요소를 찾고,

(이 요소는 public.index.html에 있습니다.)

리액트 컴포넌트를 보여줄 수 있는 루트 인스턴스를 createRoot 함수를 사용하여 생성합니다.

그리고 root.render 함수에 JSX 코드를 인자로 넣어서 보여주고 싶은 컴포넌트를 화면에 보여줍니다.

 

여기서 React.StrictMode라는 컴포넌트가 사용됐는데, 이는 리액트 프로젝트에서 앞으로 사라질 레거시 기능을 사용해

경고를 주고, 앞으로 미래의 리액트 버전에 도입될 기능들이 정상적으로 호환될 수 있도록 유도하는

개발환경에서만 활성화되는 디버깅용 컴포넌트입니다.

 

reportWebVitals는 웹 성능을 측정하는 도구인데 지금은 크게 신경 쓰지않아도 됩니다.

 

 

 

 

 

 


4.   JSX 문법

편리한 문법이지만, 올바르게 사용하려면 몇 가지 규칙을 준수해야 합니다.

 

(1)  감싸인 요소

컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나로 감싸야 합니다.

function App() {
  return (
    <h1> 리액트 안녕! </h1>
    <h2> 잘 작동하니? </h2>
  )
}

export default App;

위 코드는 정상적으로 작동하지 않습니다.

 

 

요소 여러 개가 부모 요소 하나에 의하여 감싸져 있지 않기 때문에 오류가 발생했습니다.

이 오류는 다음과 같이 코드를 작성하여 해결해야 한다.

function App() {
  return(
    <div>
      <h1> 리액트 안녕! </h1>
      <h2> 잘 작동하지? </h2>
    </div>
  )
}

export default App;

이런 식으로 요소 여러 개를 하나의 요소로 감싸야한다.

왜????

그것은 Vitual DOM에서 컴포넌트 변화를 감지해 낼 때 효율적으로 비교할 수 있도록

컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다는 규칙이 있기 때문이다.

 

 

그치만 꼭 div를 사용하지 않아도됩니다.

리액트 v16이상부터 도입된 Fragment라는 기능을 사용하면 됩니다.

function App() {
  return(
    <Fragment>
      <h1> 리액트 안녕! </h1>
      <h2> 잘 작동하지? </h2>
    </Fragment>
  )
}

export default App;

코드 상단 import 구문에서 react 모듈에 들어 있는 Fragment라는 컴포넌트를 추가로 불러옵니다.

Fragment는 다음과 같은 형태로도 표현할 수 있습니다.

function App() {
  return(
    <>
      <h1> 리액트 안녕! </h1>
      <h2> 잘 작동하지? </h2>
    </>
  )
}

export default App;

 

 

(2)  자바스크립트 표현

JSX가 단순히 DOM 요소를 렌더링하는 기능밖에 없다면 뭔가 좀 아쉬웠을 거다.

JSX 안에서는 자바스크립트 표현식을 쓸수 있는데,

자바스크립트 표현식을 작성하려면 JSX 내부에서 코드를 { } 로 감싸면 된다.

function App() {
  const name = '리액트';
  return (
    <>
      <h1> {name} 안녕 </h1>
      <h2> 잘 작동하니? </h2>
    </>
  )
}

export default App;
ES6의 const 와 let

const 는 ES6 문법에서 새로 도입되었으며 한번 지정하고 나면 변경이 불가능한 상수를 선언할 때 사용하는 키워드다. 
let동적인 값을 담을 수 있는 변수를 선언할 때 사용하는 키워드다.

ES6 이전에는 값을 담는데 var 키워드를 사용했는데 var 키워드는 scope가 함수단위다.
function myFunction() {
  var a = 'hello';
  if(true) {
    var a = 'bye';
    console.log(a); // bye
  }
  console.log(a); // bye
}

myFunction();
if 문 바깥에서 var 값을 hello로 선언하고 if 문 내부에서 bye로 설정했는데, 내부에서 재 선언했음에도 불구하고 
if 문 밖에서 a를 조회하면 변경된 값이 나온다.
이런 결점을 해결해 주는 것이 바로 let과 const다.
function myFunction() {
  let a = 1;
  if(true) {
    let a = 2;
    console.log(a); // 2
  }
  console.log(a); // 1
}

myFunction();​
let 과 const는 scope가 함수 단위가 아닌 블록 단위라, if 문 내부에서 선언한 a 값은 if 문 밖의 a 값을 변경하지 X


let 과 const를 사용할 때 같은 블록 내부에서 중복 선언이 불가능하다는 점에 주의해야 한다.
let a = 1;
let a = 2; // 오류 : Uncaught SyntaxError : Identifier 'a' has already been declared.​

그리고 const는 한번 선언하면 재설정할 수 없다.
const b = 1;
b = 2; // Uncaught TypeError : Assignment to contant variable​

 

 

 

(3)  If 문 대신 조건부 연산자

JSX 내부의 자바스크립트 표현식에서 if 문을 사용할 수는 없다.

하지만 조건에 따라 다른 내용을 렌더링해야하면 JSX 밖에서 if문을 사용하여 사전에 값을 설정하거나,

{ } 안에 조건부 연산자를 사용하면 된다.

삼항 연산자 말이다.

function App() {
  const name = '리액트';
  return (
    <div>
      {name ==='리액트' ? (
        <h1> 리액트입니다. </h1>
      ) : (
        <h2> 리액트가 아닙니다 </h2>
      )}
    </div>
  );
}

export default App;

이렇게 코드를 작성하고 저장하면 브라우저에 '리액트입니다'라는 문구를 볼 수 있다.

 

만약 const name = '뤼액트'; 로 바꾸면

'리액트가 아닙니다' 라는 문구를 볼 수 있다.

 

 

 

 

(4)  AND 연산자 (&&)를 사용한 조건부 렌더링

개발하다 보면 특정 조건을 만족할 때 내용을 보여주고, 만족하지 않으면 아무 렌더링을 하지말아야하는 상황이 있는데,

이럴 때도 조건부 연산자를 통해 구현할 수 있다.

function App() {
  const name = "뤼액트";
  return <div>{name === '리액트' ? <h1> 리액트입니다. </h1> : null} </div>;
}

export default App;

위 코드와 같이 null을 렌더링하면 아무것도 보여주지 않습니다.

 

하지만 이것보다 더 짧은 코드로 똑같은 작업을 할 수 있습니다.

바로 && 연산자를 사용해 조건부 렌더링을 하면 됩니다.

function App() {
  const name = '뤼액트';
  return <div>{name === '리액트' && <h1> 리액트입니다.</h1>}</div>;
}

export default App;

이렇게 코드를 작성하고 나면 브라우저에 아무것도 나타나지 않을 것입니다.

다시 name 값을 리액트로 설정하면 '리액트입니다.'라는 문구가 나타날 것입니다.

 

&& 연산자로 조건부 렌더링을 할 수 있는 이유는 리액트에서 false를 렌더링할 때는 null과 마찬가지로

아무것도 나타내지 않기 때문입니다.

여기서 주의할 점은 falsy한 값인 0은 예외적으로 화면에 나타나는 것입니다.

const number = 0;
return number && <div>내용</div>

이런 코드는 화면에 0을 보여줍니다.

 

 

JSX 는 언제 괄호로 감싸는가 ?
>>> 주로 JSX를 여러 줄로 작성할 때 괄호로 감싸고, 한 줄로 표현할 수 있는 JSX는 감싸지 않는다. 필수는 아니다!

 

 

 

 

(5)  undefined를 렌더링하지 않기

리액트 컴포넌트에서는 함수에서 undefined만 반환하여 렌더링하는 상황을 만들면 안 된다.

import './App.css';

function App() {
  const name = undefined
  return name;
}

export default App;

이 코드는 에러가 나타납니다.

 

어떤 값이 undefined일 수도 있다면, OR( || )연산자를 사용하면 해당 값이 undefined일 때 사용할 값을 지정할 수 있어

오류를 방지할 수 있다.

import './App.css';

function App() {
  const name = undefined
  return name || '값이 undefined입니다';
}

export default App;

 

반면 JSX 내부에서 undefined를 렌더링하는 것은 괜찮다.

import './App.css';

function App() {
  const name = undefined
  return <div> {name} </div>;
}

export default App;

 

name 값이 undefined일 때 보여주고 싶은 문구가 있다면 다음과 같이 작성하면 된다.

import './App.css';

function App() {
  const name = undefined
  return <div> {name || '리액트'}</div>;
}

export default App;

 

 

 

 

 

(6)  인라인 스타일링

리액트에서 DOM 요소에 스타일을 적용할 때는 문자열 형태로 넣는 것이 아니라 객체 형태로 넣어 주어야 한다.

스타일 이름 중에 background-color 처럼 -문자가 포함되는 이름이있는데,

이런 이름은 카멜 표기법으로 작성해야 한다.

backgroundColor 처럼

// src/App.js
function App() {
  const name='리액트';
  const style = {
    // background-color는 backgroundColor와 같이 -가 사라지고 카멜 표기법으로 작성됩니다.
    backgroundColor: 'black'
    color: 'aqua'
    fontSize: '48px', // font-size -› fontSize 
    fontWeight: 'bold', // font-weight -> fontWeight
    padding: 16 // 단위를 생략하면 pX로 지정됩니다.
  };
  return <div style={style}>{name} </div>;
}


export default App;

 

지금은 style 객체를 미리 선언하고 div의 style 값으로 지정해 줬는데

미리 선언하지 않고 바로 style 값을 지정하고 싶다면 다음과 같이 사용하면 된다.

// src/App.js

function App() {
  const name='리액트';
  return (
    <div 
      style = {{
        // background-color는 backgroundColor와 같이 -가 사라지고 카멜 표기법으로 작성됩니다.
        backgroundColor: 'black',
        color: 'aqua',
        fontSize: '48px',   // font-size -> fontSize 
        fontWeight: 'bold', // font-weight -> fontWeight
        padding: 16 // 단위를 생략하면 PX로 지정됩니다.
      }}
    >
      {name}
    </div>
  );
}

export default App;

 

 

 

 

 

(7)  class 대신 className

일반 HTML에서 CSS 클래스를 사용할 때는 <div class='myclass'></div>와 같이 class라는 속성을 설정한다.

하지만 JSX에서는 class가 아닌 className으로 설정해 줘야한다.

 

 

 

(8)  꼭 닫아야 하는 태그

HTML 코드를 작성할 때 가끔 태그를 닫지 않은 상태로 코드를 작성하기도 한다.

예를 들면, input HTML 요소는 <input></input>이라 입력하지 않고 <input>이라고만 입력해도 작동한다.

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

위 코드에서는 br과 input 태그는 열기만 하고 닫지 않았다.

 

 

JSX에서는 위 코드 처럼 태그를 닫지 않으면 에러가 발생한다.

// src/App.js 
import './App.css';

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

export default App;

이 오류를 해결하려면 태그를 닫아야 합니다!

// src/App.js 
import './App.css';

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

export default App;

 

태그 사이에 별도의 내용이 들어가지 않는 경우에는 다음과 같이 작성할 수도 있습니다.

이러한 태그를 self-closing 태그라고 부릅니다.

태그를 선언하며 동시에 닫을 수 있는 태그죠.

// src/App.js 
import './App.css';

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

export default App;

 

 

 

 

(9)  주석

JSX 안에 주석을 작성하는 방법은 일반 자바스크립트에서 주석을 작성하는 것과 조금 다릅니다.

import './App.css';

function App() {
   const name = '리액트';
   return (
     <>
       {/* 주석은 이렇게 작성합니다 */}
       <div
         className='react' // 시작 태그를 여러 줄로 작성하게 되면 여기에 주석을 작성할 수 있다.
       >
         {name}
       </div>
       //하지만 이런 주석이나
       /*이런 주석은 페이지에 그대로 나타난다*/
      <input/>
    </>
  );
}

export default App;

JSX 내부에서 주석을 작성할 때는 {/* ... */}와 같은 형식으로 작성합니다.

그리고 시작 태그를 여러 줄로 작성할 때는 내부에서 // ... 과 같은 형태의 주석도 작성할 수 있습니다.

 

만약 일반 자바스크립트에서 주석을 작성할 때처럼 아무 데나 주석을 작성하면 그 주석은 페이지에 고스란히 나타납니다.

 

 

 

'리액트' 카테고리의 다른 글

컴포넌트의 라이프사이클 메서드  (0) 2023.02.28
컴포넌트 반복  (0) 2023.02.27
ref : DOM에 이름 달기  (1) 2023.02.23
이벤트 핸들링  (0) 2023.02.20
컴포넌트  (0) 2023.02.18
Comments