JSX 내부에서 JavaScript 표현식만 사용 가능한 이유
React로 개발하면서 반드시 지켜야 하는 규칙이 있다. JSX 내부에서는 JavaScript의 모든 문법을 자유롭게 사용할 수 없고, 오직 ‘표현식(Expression)‘만 사용 가능하다는 것이다. 보통 “특정 OOO만 가능하다”는 제약은 그 기술의 깊은 원리를 이해할 수 있는 단서가 되기도 한다. 이 제약의 이유를 이해하면 React의 동작 원리를 더 깊이 파악할 수 있을 것이라 생각했다.
*Expressions
Expression At a high level, an expression is a valid unit of code that resolves to a value. There are two types of expressions: those that have side effects (such as assigning values) and those that purely evaluate. MDN
// 작동하지 않는 코드 ‼
function MyComponent() {
return (
<div>
{if (조건) {
return <span>참</span>
} else {
return <span>거짓</span>
}}
</div>
)
}
// 작동하는 코드 ✅
function MyComponent() {
return (
<div>
{조건 ? <span>참</span> : <span>거짓</span>}
</div>
)
}
MDN 문서에서 설명하듯 자바스크립트 표현식은 값을 반환한다. 하지만 더 깊이 알아보고 싶었던 건 JSX에 ‘값’만 있어야 하는 근본적인 이유였다. 살펴보니 새로운 개념이 아닌, 이미 익숙한 개념에 기반하고 있었다. 다만 이를 React와 JSX의 맥락에서 이해하는 것이 중요했다. 하나씩 살펴보자.
JSX의 역할은 마크업이다. 결국 HTML ‘값’을 반환해야 한다. 대신 그 자체로 ‘값’으로 볼 수 있는 코드(표현식)를 JSX는 그나마 유연하게 허용해준다. 위 MDN에서 표현식을 언급한 것처럼, 값 자체 외에도 ‘those that have side effects (such as assigning values)‘도 값으로 취급한다는 것이다.
React는 일종의 중개자 역할을 한다. 개발자나 사용자로부터 받은 입력(value, event)을 전달하는 것이 React의 주된 역할이며, 직접적인 연산이나 처리(statement)는 수행하지 않는다. 받은 데이터를 적절한 위치로 전달하는 것이 React의 핵심 책임이다. (마치 주문만 받고 요리는 하지 않는 ‘웨이터’다. 요리(연산 등 작업) 안하고 전달만 한다.)
render and commit
React.createElement
함수의 동작 방식// 컴포넌트 구조
function Component() {
return ( // JSX
// Markup (태그, props, {JavaScript} 활용)
);
}
컴포넌트가 반환하는 JSX 코드는 모두 React.createElement
함수의 인자로 전달된다. 여기서 함수의 ‘인자’로 전달될 수 있는 것들이라는 점이 핵심 이유다. React 공식 문서 createElement API에 따르면, 이 과정은 이렇게 진행된다.
React.createElement
함수 호출로 변환React.createElement
함수가 JavaScript 객체를 생성이 2가지가 핵심 이유 중 일부인데, 아래에서 각각 구체적으로 정리해보자.
A statement does something. An expression evaluates to a value.
이는 각각 ‘작업을 수행하는 코드’와 ‘값을 반환하는 코드’를 의미한다. 여기서 주목할 점은 expression이 statement의 일부라는 것이다(참고). expression은 평가(evaluate) 과정을 거쳐 하나의 ‘값’으로 환원되는 반면, statement는 실행 가능한(executable) 최소 단위의 독립적인 코드 조각이다. 일반적으로 statement는 하나 이상의 expression과 프로그래밍 키워드를 포함한다.
JSX는 ‘Javascript Syntax eXtension’ 또는 ‘JavaScript to XML’의 약자로 불린다. 본질적으로 마크업을 위한 도구이고, JSX 코드를 실행하면 결과적으로 HTML이 생성되어야 한다. 핵심은 HTML Node의 ‘값(value)‘을 반환하는 것이다. JavaScript가 데이터 타입에서 유연성을 보여주듯, JSX도 ‘값을 결정할 수 있는 코드’에 대해서는 유연성을 제공하는 것인지 하는 생각이 들었다. 표현식이 허용되는 이유도 JSX의 목표인 ‘값 결정’에 도움이 된다.(참고)
“중간에 조건문을 사용하고 최종적으로 값만 반환하면 되지 않을까?”라는 의문이 들 수 있다. if 조건문과 삼항 연산자의 차이를 통해 이를 살펴보자.
// statement(문)을 사용한 경우 - 반환 값이 없음
if(value){
변수 = 10;
} else {
변수 = 7;
}
// 함수 내부의 return문
function multiply(num1, num2) {
if (num1 > 0 && num2 > 0) {
return num1 * num2; // 이 return문은 함수에 속함
}
return 0;
}
// 표현식을 사용한 경우 - 값을 반환
변수 = value === true ? 10 : 7;
여기서 주목할 점은 return문의 역할이다. MDN 문서에 따르면 return은 함수를 종료하거나 함수의 반환값을 지정하는 두 가지 역할만을 수행한다(참고).
JSX 내부에서 statement를 직접 사용할 수는 없지만, React에서는 다양한 방식으로 조건부 렌더링을 구현할 수 있다. 가령 조건부 렌더링을 구현할 때 삼항연산자, map() 메소드로 충분하지 않을 수 있다. 이때는 jsx 바깥에서 js 문법으로 연산 하고 결과(값)를 jsx에 가져와서 쓰면 된다. 또 기어코 JSX 안에서 IF 문 같은 statement를 꼭 써야겠다면, 즉시 실행 함수를 활용하는 방법도 있다.
let button;
if (value) {
button = <LogoutButton />;
} else {
button = <LoginButton />;
}
return (
<nav>
<Home />
{button}
</nav>
);
function App() {
return (
<div className="App">
<h1>조건부 렌더링</h1>
<div>
{(() => {
if (condition) {
return "참입니다";
} else {
return "거짓입니다";
}
})()}
</div>
</div>
);
}
https://react-cn.github.io/react/tips/if-else-in-JSX.html
https://brunch.co.kr/@skykamja24/576