📗목차
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>
);
}
이 코드는 App이라는 컴포넌트를 만들어 준다. function 키워드를 사용하여 컴포넌트를 만들었는데 이는 함수형 컴포넌트라 부른다. 프로젝트에서 컴포넌트를 렌더링하면 함수에서 반환하고 있는 내용을 나타낸다. 함수에서 반환하는 내용을 보면 마치 HTML을 작성한 것 같지만 HTML 코드는 아니다. 이런 코드는 JSX라고 한다.
JSX는 자바스크립트의 확장 문법이며 XML과 매우 비슷하게 생겼다.
JSX는 브라우저에서 실행되기 전에 코드가 번들링되는 과정에서 바벨을 사용해 일반 자바스크립트 형태의 코드로 변환된다.
JSX는 리액트 프로젝트를 개발할 때 사용되므로 공식적인 자바스크립트 문법이 아니다.
바벨에서 여러 문법을 지원할 수 있도록 preset 및 plugin을 설정한다. 바벨을 통해 개발자들이 임의로 만든 문법, 혹은 차기 자바스크립트의 문법들을 사용할 수 있다.
HTML 코드를 작성하는 것과 비슷하기 때문에 JSX를 자주 사용하는데,
App.js에서는 App 컴포넌트가 만들어졌고, index.js 파일을 열어보면 이 App 컴포넌트를 마치 HTML 태그 쓰듯이 그냥 작성한다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
컴포넌트를 페이지에 렌더링하는 역할을 하며, react-dom 모듈을 불러와 사용 가능하다. 이 함수의 첫번째 파라미터에는 페이지에 렌더링할 내용을 JSX 형태로 작성하고, 두번째 파라미터에는 해당 JSX를 렌더링할 document 내부 요소를 설정한다.
여기서는 id가 root인 요소 안에 렌더링을 하도록 설정했다.
컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나로 감싸야 한다.
function App() {
return (
<h1>안녕</h1>
<h1>나는 프론트엔드 개발자야.</h1>
);
}
export default App;
이런 형태의 코드는 에러가 생긴다.
요소 여러 개가 부모 요소 하나에 의하여 감싸져 있지 않기 때문에 오류가 발생한다.
이 오류는 다음과 같은 코드로 해결할 수 있다.
function App() {
return (
<div>
<h1>안녕</h1>
<h1>ds</h1>
</div>
);
}
export default App;
💭 왜 요소 여러 개를 하나의 요소로 꼭 감싸줘야 할까?
그건 Virtual DOM에서 컴포넌트 변화를 감지해 낼 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다는 규칙이 있기 때문이다.
여기서 꼭 div 요소를 사용하고 싶지 않을 수도 있다. 그런 경우 리액트 v16 이상부터 도입된 Fragment라는 기능을 사용해도 된다.
import React, { Fragment } from 'react';
function App() {
return (
<Fragment>
<h1>리액트 안녕!</h1>
<h2>잘 작동하니?</h2>
</Fragment>
);
}
export default App;
Fragment는 다음과 같은 형태로도 표현 가능하다.
import React, { Fragment } from 'react';
function App() {
return (
<>
<h1>리액트 안녕!</h1>
<h2>잘 작동하니?</h2>
</>
);
}
export default App;
JSX 안에서는 자바스크립트 표현식을 쓸 수 있다. 자바스크립트 표현식을 작성하려면 JSX 내부에서 코드를 { }로 감싸면 된다.
import React from 'react';
function App() {
const name = '리액트';
return (
<div>
<h1>{name} 안녕!</h1>
<h2>잘 작동하니?</h2>
</div>
);
}
export default App;
JSX 내부의 자바스크립트 표현식에서 if문을 사용할 수 없다. 하지만 조건에 따라 다른 내용을 렌더링해야 될 때는 JSX 밖에서 if문을 사용하여 사전에 값을 설정하거나, { } 안에 조건부 연산자를 사용하면 된다. 조건부 연산자의 다른 명칭은 삼항 연산자이다.
이 연산자를 사용해보도록 하자.
import React from 'react';
function App() {
const name = '리액트';
return (
<div>
{name === '리액트' ? (
<h1>리액트입니다.</h1>
): (
<h2>리액트가 아닙니다.</h2>
)}
</div>
);
}
export default App;
특정 조건을 만족할 때 내용을 보여주고, 만족하지 않을 때 아예 아무것도 렌더링 하지 않아야 하는 상황이 올 수 있다. 이럴 때 조건부 연산자를 통해 구현 가능하다.
import React from 'react';
function App() {
const name = '리액트';
return <div>{name === '리액트' ? <h1>리액트입니다.</h1> : null}</div>;
}
export default App;
위 코드는 null을 렌더링하면 아무것도 보여주지 않는다. 하지만 이것보다 더 짧은 코드로 똑같은 작업을 할 수 있다.
다음과 같이 && 연산자를 사용해서 조건부 렌더링을 할 수 있다.
import React from 'react';
function App() {
const name = '리액트';
return <div>{name === '리액트' && <h1>리액트입니다.</h1>}</div>;
}
export default App;
&& 연산자로 조건부 렌더링을 할 수 있는 이유는 리액트에서 false를 렌더링할 때는 null과 마찬가지로 아무것도 나타나지 않기 때문이다. 한 가지 주의해야될 점은 falsy한 값인 0은 예외적으로 화면에 나타나는 것이다.
const number = 0;
return number && <div>내용</div>;
//브라우저에 0 값을 보임
💭 JSX는 언제 괄호로 감싸야 하나?
JSX를 작성할 때 (<div>Hello World</div>)
와 같이 괄호로 감쌀 때도 있고, 감싸지 않을 때도 있다. 주로 JSX를 여러 줄로 작성할 때 괄호로 감싸고, 한 줄로 표현할 수 있는 JSX는 감싸지 않는다. 괄호로 감싸는 것은 필수 사항이 아니기에 감싸도 되고 감싸지 않아도 된다.
import React from 'react';
function App() {
const name = undefined;
return name;
}
export default App;
위의 코드는 브라우저에 아무것도 나타나지 않는다.
OR(||) 연산자를 사용하면 해당 값이 undefined일 때 사용할 값을 지정할 수 있다.
import React from 'react';
function App() {
const name = undefined;
return name || '값이 undefined입니다.'
}
export default App;
name값이 undefined일 때 보여주고 싶은 문구가 있다면 다음과 같은 코드로 작성하면 된다.
import React from 'react';
function App() {
const name = undefined;
return <div>{name || '리액트'}</div>;
}
export default App;
리액트에서 DOM 요소에 스타일을 적용할 때는 문자열 형태로 넣는 것이 아니라 객체 형태로 넣어 주어야 한다. 예를 들어 background-color 처럼 '-'이 들어간 스네이크 문법이 아니라 카멜 표기법으로 작성해야 한다.
다음 예시 코드로 확인해보자.
import React from 'react';
function App() {
const name = '리액트';
const style = {
backgroundColor: 'black', // background-color
color: 'aqua',
fontSize: '48px', // font-size
fontWeight: 'bold', // font-weight
padding: 16
};
return <div style={style}>{name} </div>;
}
export default App;
위의 코드는 style 객체를 미리 선언하여 div의 style 값으로 지정해주었다.
미리 선언하지 않고 바로 style 값을 지정하고 싶다면 아래처럼 작성하면 된다.
import React from 'react';
function App() {
const name = '리액트';
return (
<div
style={{
backgroundColor: 'black', // background-color
color: 'aqua',
fontSize: '48px', // font-size
fontWeight: 'bold', // font-weight
padding: 16
}}
>
{name}
</div>
);
}
export default App;
일반 HTML에서 CSS 클래스를 사용할 때는 <div class="myclass">/div>
와 같이 class라는 속성을 설정한다. 하지만 JSX에서는 class가 아니라 className으로 설정해줘야 한다.
예시를 들어보겠다. 아래와 같이 CSS 코드를 변경해준다.
src/App.css
.react { backgroundColor: black; color: aqua; fontSize: 48px; fontWeight: bold; padding: 16px; }
CSS에서 'react'라는 클래스를 생성한 것을 App.js에서 div 요소에 넣어준다.
src/App.js
import React from 'react'; import './App.css'; function App() { const name = '리액트'; return <div className="react">{name}</div>; } export default App;
JSX를 작성할 때는 CSS 클래스를 설정하는 과정에서 className이 아닌 class 값을 설정해도 스타일이 적용되기는 한다. 하지만 Console 탭에 경고가 뜬다.
이전에는 class로 CSS 클래스를 설정할 때 오류가 발생하고 CSS 클래스가 적용되지 않았는데, 리액트 v16 이상부터는 class를 className으로 변환시켜 주고 경고를 띄운다.
HTML 코드를 작성할 때 가끔 태그를 닫지 않은 상태로 코드를 작성하기도 하는데, HTML에서는 다음과 같은 코드는 문제없이 작동한다.
<form>
성: <br>
<input><br>
이름: <br>
<input>
</form>
위의 코드는 br과 input 태그는 열기만 하고 닫지 않았다.
JSX에서는 위 코드처럼 태그를 닫지 않으면 오류가 발생한다.
다음 아래와 같이 수정해보자.
import React from 'react';
import './App.css';
>
function App() {
const name = '리액트';
return (
<>
<div className="react">{name}</div>
<input></input>
</>
);
}
export default App;
태그 사이에 별도의 내용이 들어가지 않는 경우에 self-closing 태그로 작성할 수 있다. 태그를 선언하면서 동시에 닫을 수 있는 태그이다.
import React from 'react';
import './App.css';
>
function App() {
const name = '리액트';
return (
<>
<div className="react">{name}</div>
<input/>
</>
);
}
export default App;
JSX 내부에서 주석을 작성할 때는 {/* */}와 같은 형식으로 작성한다.
import React from 'react';
import './App.css';
function App() {
const name = '리액트';
return (
<>
{/* 주석은 이렇게 작성한다. */}
<div className="react">{name}</div>
// 하지만 이런 주석이나
/* 이런 주석은 페이지에 그대로 나타나게 된다. */
<input/>
</>
);
}
export default App;
JSX를 작성할 때는 코드의 가독성을 위해 들여쓰기를 사용한다.
아래 코드를 보자.
import React from 'react';
import './App.css';
function App() {
const name = '리액트';
return (
<>
<div className="react">{
name
}</div>
<h1>안녕?</h1>
<h2>난 리액트야.</h2>
<p>코드가 굉장히 난잡하지?</p>
</>
);
}
export default App;
난잡한 이 코드를 정리해보자.
VS Code에서 F1을 누르고 format이라고 입력한 다음 Enter를 누르면 아래와 같이 정렬된다.
import React from 'react';
import './App.css';
function App() {
const name = '리액트';
return (
<>
<div className="react">{
name
}</div>
<h1>안녕?</h1>
<h2>난 리액트야.</h2>
<p>코드가 굉장히 난잡하지?</p>
</>
);
}
export default App;
참고문헌
김민준,「리액트를 다루는 기술 :실무에서 알아야 할 기술은 따로 있다!」, 길벗, 개정판[실은 2판] 2019 (개정판)