이 글은 김민준(velopert)님의 리액트를 다루는 기술을 참조하였습니다.
목차
1. 리액트 파일 구조
2. What is JSX?
3. JSX 문법
1. 리액트 파일 구조
본격적으로 시작하기 전에 리액트를 처음 설치하면 생소한 것들이 엄청 많다.
create-react-app 명령어를 bash에 쳐서 아무 앱이나 하나 생성해보자
여기서 App.js를 확인해보면 이렇게 코드가 작성되어 있다.
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;
처음에 코드를 봤을 때, '이런 느낌이겠구나~'라는 감이 전혀 오질 않는다.
분명 JS인데 난데없이 HTML 태그를 반환시키질 않나. import로 다른 모듈을 불러오질 않나.
처음 사용하는 사람에게 있어서 익숙한 코드는 아닐 것이다.
이게 바로 JSX라는 것인데, 그전에 import를 한 번 눈여겨 보자.
import logo from './logo.svg';
import './App.css';
JSX가 뭔지는 아직 모르지만 분명한 건 브라우저 환경에서 모듈을 import해서 사용하는 것 지원하지 않는 기능이다.
리액트에서 모듈을 import 기능을 사용하기 위해서는 번들(bundle)로 파일들을 하나로 엮어줄 필요가 있었는데
여기서 자주 사용되는 번들러로 Webpack이 있다.
웹팩을 이용하면 import로 불러온 파일들끼리 관계를 형성하여 하나 혹은 다수의 파일로 생성해준다.
웹팩을 다룰 줄 알면 좋지만 일단은 create-react-app이 이런 작업을 모두 대신해주기 때문에
지금 당장은 별도의 작업을 할 필요는 없고, 그냥 이런게 있구나~ 하고 넘어가면 된다.
2. What is JSX?
JS의 확장문법이자 XML과 비슷하게 생겼다는데, 내가 아직 XML을 안 해서 거기까진 모르겠다.
비슷하게 생길 수밖에 없는 게 JSX가 애초에 JavaScript XML의 약자기 때문이다.
하지만 JSX는 공식적으로 지원하는 언어가 아니다. 따라서 번들링되는 과정에서 바벨을 사용해
우리가 기존에 알고 있던 JS 형태의 코드로 변환되어야 한다.
(아, 물론 이것도 우리가 직접하진 않고 알아서 해준다.)
function App() {
return (
<div>
Hello, <b>world</b>
</div>
);
}
이렇게 작성된 코드가 번들링되면 다음과 같이 변환된다.
function App() {
return React.createElement("div", null, "Hello, ", React.createElement("b", null, "world"));
}
왜 굳이 JSX여야 하느냐?
위의 변환된 코드를 확인해보면 확실히 이해할 수 있듯이 HTML 태그로 코드를 작성하는 것이
가독성이 훨씬 높고 유지 보수가 편해지기 때문이다.
하지만 새로운 언어를 배우겠다면 역시 문법을 처음부터 다시 배워야 한다.
문법으로 넘어가기 전에 index.js를 확인하면 한 가지 알 수 없는 기능이 있다.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
React.StrictMode로 감싸져 있는데 이건 리액트 레거시 기능을 사용하지 못 하도록
리액트 프로젝트에서 자체적으로 막아버린 것이다.
레거시 기능이란 예전에나 사용하고 이제는 사라질 일만 남은 옛날 기능들인데 이것들을 사용하려 하면 경고 표시가 뜬다.
3. JSX 문법
1. 반드시 하나의 부모 요소로 다른 요소들을 감싸주어야 한다.
왼쪽은 여러 요소를 return하려고 하니까 작동하질 않는다. 그래서 오른쪽처럼 하나의 부모 태그로 묶어야 작동한다.
그 이유는 VDOM에서 컴포넌트의 변화를 감지했을 때 효율적으로 비교하기 위함이다.
때문에 컴포넌트 내부는 하나의 DOM Tree 구조로 이루어져 있어야 한다는 규칙이 존재한다.
굳이 div 같은 태그로 묶기 싫다면 <Fragment></Fragment> 혹은 <></>로도 묶어줄 수 있다.
2. 자바스크립트 표현
React는 자바스크립트 표현식을 사용할 수 있다.
import './App.css';
function App() {
const where = 'world';
return (
<div>
<div>Hello, </div>
<div>{where}</div>
</div>
);
}
export default App;
참고로 const 키워드를 이용했는데 이외에도 var, let이 있다.
차이는 scope와 수정 가능 여부로 갈리는데 리액트는 애초에 수정할 일이 있는 변수를 주로 다루는 방법이 있다.
따라서 특별한 목적이 있는 게 아니라면 const로 값을 고정시켜버리는 것이 낫다.
3. 조건문(if, for) 대신에 조건부 연산자(삼항/조건부 연산자) 사용
import './App.css';
function App() {
const house = '집';
return (
<>
{house === '말'
? <h1>집입니다.</h1>
: <h1>집이 아닙니다.</h1>
}
</>
);
}
export default App;
이건 나도 처음 안 사실인데 if, for문은 JS 표현식이 아니라서 JSX 내부 자바스크립트 표현식에서 사용이 안 된다.
if문을 사용하지 못 하는 것은 아니다. 예를 들어, 조건에 따라 렌더링할 내용을 나누어야 할 경우에는
JSX 밖에서 if문을 통해 렌더링할 data를 컨트롤할 수 있다.
4. AND(&&) 연산자
원래 이 부분을 작성 안 하고 넘어갔었는데, 나중에 꽤 재밌는 방법으로 써먹을 수 있길래 급하게 추가했다.
AND 연산자로 구현 가능한 내용은 조건부 연산자로 모두 커버가 되긴 하지만, AND연산자로 더 짧게 표현할 수 있는 경우가 있다.
function App() {
const topic = 'React';
return <div>{name === "HTML" ? <h1>HTML</h1> : null}</div>;
}
export default App;
function App() {
const topic = 'React';
return <div>{name === "HTML" && <h1>HTML</h1>}</div>;
}
export default App;
위의 코드와 아래의 코드는 똑같이 동작한다. 똑같이 화면에 아무것도 출력되지 않는다.
이건 React가 false를 렌더링할 때는 null과 마찬가지로 아무것도 나타나지 않기 때문.
즉 논리 연산 && 를 실행했을 때, name==="HTML" 이 false를 return하므로 화면에 아무것도 출력되지 않는다.
💡 주의할 점
여기선 falsy(거짓 같은 값)한 값인 0은 예외적으로 화면에 출력이 된다.
5. undefined를 렌더링 방지
import './App.css';
function App() {
const token = undefined;
return token;
}
export default App;
나중에 토큰 발급을 하게 되는 경우에 정상적으로 발급받지 못 한 경우 undefined가 될 수도 있다.
따라서 OR(||) 연산자로 해당 값이 정상적으로 할당되지 않았을 경우를 예외 처리 해준다.
import './App.css';
function App() {
const toekn = undefined;
return token || "토큰 오류";
}
export default App;
또한 JSX 내부에서 undefined를 렌더링하는 것은 괜찮다.
import './App.css';
function App() {
const token = undefined;
return (
<div>
{token}
</div>
);
}
export default App;
6. 인라인 스타일링
DOM 요소에 style 속성을 적용시킬 때는 문자열이 아니라 객체 형태로 설정한다.
import './App.css';
function App() {
const house = '집';
return (
<div style = {{
backgroundColor: '#FFA348',
fontSize: '30px',
}}>{house}</div>
);
}
export default App;
import './App.css';
function App() {
const house = '집';
const style = {
backgroundColor: '#FFA348',
fontSize: '30px',
}
return (
<div style={style}>{house}</div>
);
}
export default App;
두 방법 모두 유효하다.
7. className
HTML에서는 CSS를 적용하기 위해 class로 지정해주었지만 JSX에서는 className으로 설정한다.
아마 class도 적용이 되긴 하는데 잠재적 오류가 있다고 뜨는 걸로 안다.
8. 태그는 꼭 닫기
import './App.css';
function App() {
return (
<div>
<input></input>
<input />
</div>
);
}
export default App;
HTML에선 input태그를 굳이 닫지 않은 경우도 많았지만, JSX는 그렇지 않다.
따라서 반드시 태그를 닫아주어야 하는데 만약 input태그 사이에 다른 내용이 들어가지 않는다면
self-closing 태그라고 불리는 방법으로 선언과 동시에 닫을 수 있다.
9. 주석
import './App.css';
function App() {
return (
<>
// 얘랑
/* 얘는 페이지에서 볼 수 있다. */
{/* */}
<div>
피곤하다..
</div>
</>
);
}
export default App;
일반적으로 JS에서 사용하는 주석은 JSX에서 노출되기 때문에 {/* */}로 주석처리를 해준다.