반응형
엘리먼트(element)란?
- 엘리먼트(element)는 View에 렌더링 할 내용을 React에 알려주기 위한 수단으로, React 애플리케이션을 구성하는 가장 작은 블록이다.
const element = <p className="greeting">Hello, World</p>
- React 엘리먼트는 HTML 태그의 이름을 값으로 가지는 type 필드와 그 외 속성들을 값으로 전달받는 props 필드로 구성된 객체(object) 형태로 정의되며, React는 이 객체를 읽어들여 DOM을 구성하고 최신 상태로 업데이트하는데 사용한다.
- React 엘리먼트는 일반 객체(plain object)로 손쉽게 생성할 수 있지만, 불변 객체(immutable object)이기 때문에 일단 생성된 후에는 상태나 속성을 변경할 수 없다. 따라서 React에서 UI를 업데이트하는 방법은 새로운 엘리먼트를 생성하고, 이를 render() 메소드에 전달하는 것이다.
루트 DOM 노드(Root DOM Node)
- React 애플리케이션에는 id 속성값이 root인 <div>요소가 하나 존재한다. 이를 루트 DOM 노드(Root DOM Node)라고 부르며, 이 내부에 들어가는 모든 요소들은 React DOM에서 관리한다.
- React 애플리케이션은 일반적으로 하나의 루트 DOM 노드를 가지지만, 기존 애플리케이션에 React를 순차적으로 도입하려는 경우에는 원하는 만큼의 독립된 루트 DOM 노드를 포함할 수도 있습니다.
<div id="root">
<h1>Hello, World!</h1>
<p>React도 안녕!</p>
</div>
엘리먼트의 렌더링
- index.js 파일은 React 애플리케이션의 진입점이며, 초기 코드는 아래와 같다.
- 우선 루트 DOM 요소를 createRoot() 함수에 전달하여 새로운 루트 DOM 노드를 생성하여 반환한다. 이렇게 반환된 루트 DOM 노드의 render() 메소드에 화면에 나타내길 원하는 엘리먼트들을 전달하여 View를 렌더링하게 된다.
// index.js의 초기 코드
import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const root = createRoot(document.getElementById("root"));
root.render(
<StrictMode>
<App />
</StrictMode>
);
// 새롭게 생성한 element라는 React 엘리먼트를 화면에 렌더링한 index.js
import { createRoot } from "react-dom/client";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const element = <h1>새로운 React 엘리먼트</h1>;
root.render(element);
컴포넌트(component)란?
- React에서 컴포넌트란 자바스크립트 함수의 개념과 비슷하게 이해할 수 있다. React에서는 애플리케이션의 UI를 설계할 때 사용자가 볼 수 있는 화면을 여러 개의 컴포넌트로 나누어 구성함으로써 각각의 컴포넌트를 개별적으로 관리할 수 있다.
- 이러한 컴포넌트는 단순히 재사용이 가능한 템플릿의 역할 뿐만 아니라, 데이터(props)를 입력 받아 View의 상태에 따라 화면에 어떻게 표시되는지를 정의하는 React 엘리먼트를 반환한다.
- React 컴포넌트는 선언하는 방식에 따라 클래스 기반의 컴포넌트와 함수 기반의 컴포넌트로 구분할 수 있다.
클래스 컴포넌트와 함수 컴포넌트
- 지금까지 살펴본 App 컴포넌트는 function 키워드를 사용한 함수 컴포넌트다. 이처럼 컴포넌트를 정의하는 가장 간단한 방법은 자바스크립트 함수를 작성하는 것이다.
// 함수 기반의 App 컴포넌트
export default function App() {
return (
<div>
<h1>Hello, World!</h1>
</div>
);
}
- class 키워드를 사용하여 클래스 기반의 컴포넌트를 정의할 수도 있다. 클래스 컴포넌트는 Component 클래스를 상속해야 하며, render() 메서드를 반드시 구현해야 한다. 그리고 render() 메서드를 통해 화면에 보여주어야 할 JSX 표현식(expression)을 반환하면 된다.
// 클래스 기반의 App 컴포넌트
import React from "react";
export default class App extends React.Component {
render() {
return <h1>Hello, World!</h1>;
}
}
- React에서 이 두 가지 유형의 컴포넌트는 기능적으로 완전히 동일하게 동작한다. 단지 클래스 컴포넌트는 state 기능과 생명 주기 메소드를 사용할 수 있지만, 함수 컴포넌트에서는 해당 기능들을 사용할 수 없다는 차이점만 있었다.
- 하지만 함수 컴포넌트는 클래스 컴포넌트보다 선언하는 방법이 훨씬 간결하고, 메모리의 소비 또한 적다는 장점을 가진다. 그리고 state 기능과 생명 주기 메소드의 사용이 불가능하다는 단점 또한 React v16.8부터 새롭게 추가된 Hook을 사용함으로써 더 이상 문제가 되지 않게 되었다.
- 그래서 React 공식 문서에서는 클래스 컴포넌트보다는 함수 컴포넌트와 Hook의 사용을 권장하고 있다.
컴포넌트의 생성
- 새로운 컴포넌트를 생성하기 위해 우선 React 프로젝트의 src 폴더에 파일을 생성한다.
- React에서 컴포넌트를 생성할 때는 반드시 컴포넌트의 이름을 대문자로 시작하도록 작성해야 한다. React는 소문자로 시작하는 이름의 컴포넌트를 <h1>이나 <div>와 같은 정규 HTML 태그로 취급하기 때문이다.
- 소문자로 시작하는 내장 컴포넌트는 ‘h1’이나 ‘div’ 같은 문자열 형태로 React.createElement() 메소드에 전달되지만, <Greeting />과 같이 대문자로 시작되는 사용자 정의 컴포넌트는 React.createElement(Greeting)의 형태로 컴파일 되어 자바스크립트 파일에서 사용자가 직접 정의했거나 import를 통해 가져온 컴포넌트를 가리키게 된다.
// Greeting.js
function Greeting() {
return (
<>
<h1>React Component</h1>
<p>나의 첫 React 컴포넌트!</p>
</>
);
}
export default Greeting;
// App.js
import Greeting from "./Greeting";
function App() {
return <Greeting />;
}
export default App;
- 사용자 정의 컴포넌트를 사용하는 이유는 React.createElement() 메소드의 호출이나 JSX 구문으로 생성하는 Virtual DOM의 생성 코드를 사용자 정의 컴포넌트 쪽으로 이동시킴으로써 코드를 간결하게 만드는 데 그 목적이 있다.
export와 import
React 모듈의 기본 구조
- React에서 모듈의 코드는 일반적으로 import문-컴포넌트 코드-export문의 구조를 따라 작성된다.
// App.js
import Greeting from "./Greeting";
function App() {
return <Greeting />;
}
export default App;
- 코드 상단에 위치한 import 문은 다른 곳에 정의된 코드를 App.js 파일 내에서 사용할 수 있도록 불러오는 구문이다.
- 그 다음으로 function 키워드를 사용하여 함수 기반의 App 컴포넌트를 선언하고 있다. 이때 앞서 import한 Greeting 컴포넌트를 사용자 정의 컴포넌트로 사용하고 있다.
- 마지막으로 코드 하단에 위치한 export 문은 위에서 선언한 App 컴포넌트를 다른 모듈에서 불러와 사용할 수 있도록 내보낸다는 의미다.
모듈 내보내기
- 내보내길 원하는 변수나 함수, 클래스 앞에 export 키워드를 붙여주기만 하면 모듈을 내보낼 수 있으며, 이를 named export라고 부른다.
// 선언과 동시에 내보내기
export default function App() {
return <Greeting />;
}
// 선언과 별도로 내보내기
function App() {
return <Greeting />;
}
export default App;
- React에서 모듈은 크게 두 가지 유형으로 구분할 수 있다.
- 하나의 컴포넌트만 선언되어 있는 모듈
- 복수의 컴포넌트가 선언되어 있는 라이브러리 형태의 모듈
- 대부분 1번 유형처럼 하나의 파일에 하나의 컴포넌트 만을 선언하여 사용하는 경우가 일반적이다. 만약 2번 유형처럼 하나의 파일에 복수의 컴포넌트를 선언하고, 여러 컴포넌트를 내보내고 싶다면 각각의 컴포넌트 선언부에 export 키워드를 붙여주면 된다.
export function GetBrand() {
return <h1>내 노트북은 Samsung 노트북입니다.</h1>;
}
export function GetOS() {
return <h2>내 노트북의 OS는 Windows입니다.</h2>;
}
- 만약 선언부에 각각 export 키워드를 붙여주는 것이 귀찮다면 아래 코드처럼 중괄호({})를 사용하여 한 번에 내보낼 수도 있다.
function GetBrand() {
return <h1>내 노트북은 Samsung 노트북입니다.</h1>;
}
function GetOS() {
return <h2>내 노트북의 OS는 Windows입니다.</h2>;
}
export { GetBrand, GetOS };
모듈 불러오기
- React에서는 import 키워드와 중괄호({})를 사용하여 다른 파일에서 특정 컴포넌트를 불러올 수 있다. import될 때 사용되는 이름은 원래 파일에서 선언된 이름을 그대로 사용해야 한다.
import { GetBrand, GetOS } from "./Laptop";
export default function App() {
return (
<>
<GetBrand />
<GetOS />
</>
);
}
- 만약 불러올 컴포넌트의 개수가 많다면 ‘import * as <object>’구문을 사용하여 객체 형태로 원하는 컴포넌트들을 한 번에 불러올 수도 있지만 이 경우에는 사용할 때 ‘laptop.’이라는 별명이 추가되어야 하므로 코드가 좀 더 복잡해진다.
import * as laptop from "./Laptop";
export default function App() {
return (
<>
<laptop.GetBrand />
<laptop.GetOS />
</>
);
}
- React에서는 가급적 첫 번째 예제처럼 다른 파일에서 가져오는 컴포넌트의 이름을 구체적으로 명시하는 것이 좋다.
다른 이름으로 불러오기
- as 키워드를 사용하면 원래 파일에서 선언한 이름과는 다른 이름으로 컴포넌트를 불러올 수 있다.
import { GetBrand as Brand, GetOS as OS } from "./Laptop";
export default function App() {
return (
<>
<Brand />
<OS />
</>
);
}
export default
- export default 구문을 통해 ‘해당 파일에서는 하나의 컴포넌트만을 내보낸다’는 의미를 명확히 나타낼 수 있다.
export default App;
- export default 구문을 사용하여 내보낸 컴포넌트는 중괄호({})를 사용하지 않고 불러올 수 있으며, 이름 또한 원하는 이름으로 바꿔서 불러올 수 있다.
// Laptop.js
export default function GetBrand() {
return <h1>내 노트북은 Samsung 노트북입니다.</h1>;
}
export function GetOS() {
return <h2>내 노트북의 OS는 Windows입니다.</h2>;
}
// App.js
import Brand from "./Laptop";
export default function App() {
return <Brand />;
}
- 위의 예제처럼 한 파일 내에서 default export 구문과 named export 구문을 동시에 사용하는 경우는 실제로는 흔치 않다. 보통 하나의 파일에는 하나의 default export 구문 만을 사용하거나, default export 구문을 사용하지 않고 하나 또는 여러 개의 named export 구문을 사용하는 것이 보다 일반적이다.
화살표 함수(arrow function)
- default export 구문은 하나의 파일에 단 하나만 존재해야 하고, 이름 또한 원하는 이름으로 불러올 수 있기 때문에 default export 구문을 사용할 컴포넌트는 선언할 때 이름이 없어도 괜찮다.
export default function () {
return <h1>내 노트북은 Samsung 노트북입니다.</h1>;
}
- ES6 문법부터 추가된 화살표 함수(arrow function)는 function 키워드 대신 화살표 기호(⇒)를 사용함으로써 함수 컴포넌트를 손쉽게 선언할 수 있도록 해준다. 화살표 함수는 함수의 이름을 설정할 수 없기 때문에 기존 자바스크립트에서 사용된 익명 함수(anonymous function)처럼 함수를 선언하고 바로 변수나 상수에 대입하는 방식으로 사용한다.
const GetBrand = () => {
return <h1>내 노트북은 Samsung 노트북입니다.</h1>;
};
export default GetBrand;
Reference
반응형
'Development > ReactJs' 카테고리의 다른 글
[React] 리액트 이벤트 핸들링 - 이벤트 핸들링 및 전파 (0) | 2025.03.07 |
---|---|
[React] 리액트 컴포넌트 스타일링 - Css, Sass, Css Module, Styled-components (0) | 2025.03.07 |
[React] 리액트 데이터 관리 - Props, State (1) | 2024.11.19 |
[React] 리액트 JSX - 정의, 모듈, 문법, DOM 속성 (2) | 2024.11.18 |
[React] 리액트 개요 - SPA, 라이브러리, Virtual DOM, 개발환경 및 세팅 (0) | 2024.11.18 |