Study/React
React.js - JSX
김만두_
2023. 6. 21. 20:22
JSX 란
const element = <h1>Hello, world!</h1>;
위에 희한한 태그 문법은 문자열도, HTML도 아니다.
JSX라 하며 JavaScript를 확장한 문법이다. JSX라고 하면 템플릿 언어가 떠오를 수도 있지만, JavaScript의 모든 기능이 포함되어 있다.
JSX는 React “엘리먼트(element)” 를 생성한다.
JSX 변환 과정
- JSX는 브라우저에서 실행되기 전에 코드가 번들링되는 과정에서 바벨을 사용하여 자바스크립트 형태로 변환된다.
// JSX const element = ( <h1 className="greeting"> Hello, world! </h1> ); // JS로 변환된 JSX const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );
- JSX를 사용하지 않고 React.createElement() 함수를 사용하면 컴포넌트를 렌더링 할 수 있다. 하지만 이 방식은 JSX를 사용하는 방식보다 불편하다. JSX를 사용하면 쉽고 편하게 UI를 렌더링 할 수 있다.
JSX 장점
- 보기 쉽고 익숙하다.
- JSX는 HTML 코드와 비슷하기 때문에 일반 자바스크립만 사용한 코드보다 더 익숙하며 가독성이 좋다.
- 높은 활용도
- JSX에는 div, span 같은 HTML 태그를 사용할 수 있으며, 개발자가 만든 컴포넌트도 JSX 안에서 작성할 수 있다.
JSX 문법
반드시 태그는 닫혀야 한다.
- <div>, <p>, <span>, <a> 같이 짝이 있는 태그의 경우 반드시 닫는 태그가 존재해야 한다. 그렇지 않을 경우 에러가 발생한다.
- <img/>, <input/>, <br/> 같은 단독 태그(self-closing tag)의 경우에는 반드시 태그를 닫아줘야 한다. 그렇지 않을 경우 에러가 발생한다.
렌더링 될 루트 엘리먼트는 하나만 존재 해야 한다.
ReactDOM.render(
<div>
Hello
</div>
<div>
Bye
</div>,
document.getElementById('root')
);
- 위 예제처럼 렌더링 될 리액트 엘리먼트에서 루트 엘리먼트가 두 개 이상일 경우 에러가 발생한다. 때문에 두 개 이상의 루트 엘리먼트가 존재할 경우 아래와 같이 반드시 하나의 엘리먼트로 감싸져야 한다. (JSX는 자식 엘리먼트를 가질 수 있다.)
- Virtual DOM에서 컴포넌트 변화를 감지해 낼 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리 구조로 이루어져야 한다는 규칙 때문에, 리액트에서는 반드시 컴포넌트에 여러 요소가 있다면 반드시 부모 요소로 감싸야 한다.
ReactDOM.render(
<div>
<div>
Hello
</div>
<div>
Bye
</div>
</div>,
document.getElementById('root')
);
- 이처럼 하나의 엘리먼트로 감싸져야 하는 경우 무분멸한 div 태그를 사용하게 되고, 스타일 관련 코드가 꼬일 수도 있다. 이를 위해 리액트에서는 복수의 엘리먼트를 리턴하는 방법을 제공한다.
JS 표현식 사용하기
- JSX에서는 중괄호 { } 를 사용하여 JS 표현식을 쓸 수 있다.
const name = 'Josh Perez'; const element = <h1>Hello, {name}</h1>; // Hello, Josh Perez ReactDOM.render( element, document.getElementById('root') ); //--------------------------------------------------------------------------- ReactDOM.render( <p>Random number : {Math.random() * 100}</p>, document.getElementById('root') ); // 중괄호는 표현식 먼저 평가 돼 그 결과를 리턴하게 만든다. //--------------------------------------------------------------------------- // 주석 사용하기 // JSX에서 주석은 {}로 감싸준다. 여러 줄 주석만 사용 가능하다. ReactDOM.render( <div> <p>Hello</p> {/* 주석은 이렇게 작성합니다. */} <p className='react' // 시작 태그를 여러줄로 작성 시 주석 작성 가능 >World</p> // 하지만 이런 주석이나 /* 이런 주석은 페이지에 그대로 노출됩니다.*/ </div>, document.getElementById('app') );
조건부 렌더링
삼항 연산자(조건부 연산자)를 사용한 조건부 렌더링
- JSX 내부의 JS 표현식에서는 if문을 사용할 수 없다. 때문에 조건에 따라 다른 내용을 렌더링 하고자 할 경우 JSX 밖에서 if 문을 사용하거나, 중괄호 안에서 삼항 연산자를 사용하면 된다.
class App extends Component { render() { let name = 'React'; return ( <div> { name === 'React' ? ( <h1>This is React.</h1> ) : ( <h1>This is not React.</h1> ) } </div> ); } }
AND 연산자(&&)를 사용한 조건부 렌더링
- 특정 조건을 만족할 때만 내용을 보여주고 싶을 때 사용
class App extends Component { render() { let name = 'React'; return ( <div> { name === 'React' && <h1>This is React.</h1> } </div> ); } }
OR 연산자(||)를 사용한 조건부 렌더링
- 리액트 컴포넌트에서는 함수에서 undefined나 null을 반환하면 렌더링을 하려하면 오류가 발생한다. 반면 JSX 내부에서 undefined나 null을 렌더링하는 것은 괜찮다.
- JSX 내부에서 undefined나 null을 렌더링하면 아무것도 보여주지 않는다.
- OR 연산자는 AND 연산자와 다르게 특정 값이 undefined나 null일 경우 보여주고 싶은 문구가 있을 때 주로 사용한다.
class App extends Component { render() { let name = undefined; return ( <div> { name === 'React' || <h1>This is React.</h1> } </div> ); } }
JSX에서 속성 정의하기
- HTML 엘리먼트에 속성을 정의할 수 있는 것처럼, JSX에서도 엘리먼트에 속성을 정의 할 수 있다. 하지만 JSX는 HTML보다는 JavaScript에 가깝기 때문에 JSX에서는 HTML 엘리먼트에 속성을 정의하는 방식과는 약간 다른 방식으로 속성을 정의 한다.
- JXS가 반환하는 React DOM 엘리먼트에서는 기존 HTML 속성이 아닌 camelCase로 작성된 속성명을 사용해야 한다. 예를 들어, JSX에서 class는 className이 되고 tabindex는 tabIndex가 된다.
- className이 아닌 class 값을 설정 시 스타일이 설정은 되지만 경고 문구가 뜬다. 하지만 v16 이상 부터는 class를 className으로 변환시켜주고 경고를 띄워준다.
- JSX에서 속성값을 정의 할 때 중괄호 { }를 사용하여 JS 표현식을 사용할 수 있는데 이 경우 따옴표를 사용하지 않는다.
// JSX에서 프로퍼티 명은 카멜케이스로 작성되어야 한다. const element = <div tabIndex="0"></div>; // 속성값 정의 시 JS 표현식을 사용고자자 할 경우 따옴표를 사용하지 않는다. const element = <img src={user.avatarUrl}/>;
- 속성값 정의 방법
- 따옴표를 사용하여 문자열 입력 → 정적
- 중괄호를 사용하여 JS표현식 사용. 이 경우에는 따옴표를 사용하지 않음 → 동적
- 속성값을 정의 할 경우 위 두 가지 방법 중 하나만 사용해야 하며, 동일한 속성에 위 두가지 방법을 사용할 수 없다. 한 속성에 하나의 방식만 사용해야 한다.
인라인 스타일링
- JSX에서는 style 속성 안에 직접 CSS를 포함할 수 없으며, 스타일 정보를 담은 객체를 참조해야한다. 스타일 객체의 경우 기존 CSS 속성 명을 camelCase로 작성한다.
var element = <div style="color:red;">Hello World</div>; // 인라인 CSS 사용불가 //-------------------------------------------------------------------- // JXS에서 CSS를 적용하기 위해서는 스타일 객체를 만들어야 한다. var styleObject = { color: "#333", padding: 0, backgroundColor: "black", // 스타일 각체의 속성은 모두 camelCase로 작성한다. fontSize: "32" } var element = <div style={styleObject}>Hello World</div>; //-------------------------------------------------------------------- // 스타일 객체를 style 속성 내부에 선언 가능 var element = <div style={ { color: "#333", fontSize: "32" } }> Hello World </div>;
JSX 특징
대소문자를 구별한다.
- JSX에서 HTML엘리먼트를 작성할 때는 반드시 소문자를 사용해야 하지만, 컴포넌트를 작성할 때는 컴포넌트 클래스 이름과 동일하게 PascalCase로 작성되어야 한다.
ReactDOM.render( <div> <MyCustomComponent/> </div>, document.getElementById('root') );
주입공격을 방지한다.
- 기본적으로 React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프 처리하므로, 애플리케이션에서 명시적으로 작성되지 않은 내용은 주입되지 않는다. 모든 항목은 렌더링 되기 전에 문자열로 변환된다. 이런 특성으로 인해 XSS (cross-site-scripting) 공격을 방지할 수 있다.
객체를 표현한다.
- Babel은 JSX를 React.createElement() 호출로 트랜스파일한다. 때문에 첫 번째 코드는 두 번째 코드로 트랜스 파일 된다.
- // 개발자가 작성한 코드 const element = ( <h1 className="greeting"> Hello, world! </h1> ); // babel로트랜스 파일된 코드 const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );
- React.createElement()는 버그가 없는 코드를 작성하는 데 도움이 되도록 몇 가지 검사를 수행 후, 기본적으로 다음과 같은 객체를 생성한다.
- const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } }
- 이렇게 생성된 객체를 “React 엘리먼트”라고 하며, 이는 화면에 표시하려는 항목에 대한 설명이라고 할 수 있다. React는 이러한 객체를 읽고 DOM을 구성하고 최신으로 유지하는 데 이러한 객체를 사용한다.