저번 글에서 간단한 예시를 바탕으로 createElement와 render()를 사용해보았습니다. 이제 이를 바탕으로 React의 핵심인 컴포넌트를 만들어 볼 차례입니다.
React에서 컴포넌트를 직접 만드는 방법은 두 가지로 나뉩니다. 바로 Class와 Function입니다.
그 중 먼저 Class에 대해 살펴보도록 하죠.
class ClassComponent extends React.Component {
render() {
return (<div>"React!"</div>)
}
}
문법은 위 코드 블럭과 같습니다. 먼저 class와 식별자를 사용하여 class를 생성한 뒤, extends로 React.Component를 상속받아 class 컴포넌트를 만든다는 것을 선언합니다.
그런 뒤, render 함수와 실제로 렌더링하고 싶은 내용을 작성해줍니다.
물론 여기서 끝은 아니에요! 컴포넌트를 만들기만 하고 호출을 안해줬죠? 그러니까 밑의 코드 블럭처럼 실제 컴포넌트를 불러와 주는 코드도 작성해야 실제로 화면에 출력될 거에요.
ReactDOM.render(
<ClassComponent />, document.querySelector('#root')
)
이제 우리가 class 방식으로 만든 ClassComponent는 id가 root인 요소에 성공적으로 출력되게 됩니다.
function 컴포넌트를 만드는 건 사실 class와 별반 다르지 않습니다. 그냥 기명 함수를 만들고 Element를 반환하는 함수 내용을 적어주면 그만이에요.
function FunctionComponent1() {
return (<div>"React!"</div>)
}
function FunctionComponent2 = () => {
return (<div>"React!"</div>)
}
함수의 형태만 취하면 되는 거라, 아래쪽 코드처럼 화살표 함수를 사용해서 작성해도 전혀 무방합니다. 두 코드는 완벽히 같은 코드에요.
실제로 화면에 출력되게끔 호출하는 방식은 class와 동일합니다.
위의 두 가지 방법말고, 우리는 저번에 다루었던 createElement로도 컴포넌트를 만들 수 있습니다. 다만 class나 function처럼 직접 선언하는 것이 아니라, render 메서드의 인자로 넣을 수 있습니다.
하지만 그 전에, 먼저 createElement의 문법을 정확하게 알고 넘어갑시다.
React.createElement(
type, // 태그 이름, React 컴포넌트, React.Fragment
[props], // React 컴포넌트에 넣어주는 데이터 객체
[...children] // 컴포넌트의 자식으로 넣어주는 요소들
)
createElement의 인자로는 3가지 유형이 들어가는 데, type, [props], [...children]입니다. 일단 이번 글에서는 type에 따른 컴포넌트 작성에 초점을 둘 것이고, props와 children 부분은 조만간 새로운 게시물에서 면밀히 다루려고 합니다.
그러면 위 코드 블럭의 주석을 유념하면서 실제 예시를 한번 만들어 보겠습니다.
// 태그 이름 사용
ReactDOM.render(
React.createElement('h1', null, '태그 이름 사용!'),
document.querySelector('#root')
)
// React 컴포넌트 사용
const Component = () => {
return <h1>컴포넌트 사용!</h1>
}
ReactDOM.render(
React.createElement(Component, null, null),
document.querySelector('#root')
)
// React.Fragment 사용
ReactDOM.render(
React.createElement(React.Fragment, null, 'Fragment 사용!'),
document.querySelector('#root')
)
(참고로 props 부분은 여기서 자세히 다루지 않기 때문에 공통적으로 null을 넣어주었습니다.)
태그 이름을 사용하거나 컴포넌트를 직접 createElement에 넣는 것은 예시를 읽는 것만으로도 쉽게 이해가 됩니다. 그렇다면 세번째 React.Fragment는 뭘까요?
일단 성공적으로 'Fragment 사용!'이라는 글이 화면에 출력되긴 했습니다.
그런데 콘솔로 살펴보면, React.Fragment를 사용해서 만든 컴포넌트는 따로 요소로 처리되지 않고 root div에 날 것의 문자로 들어가 있습니다.
위 이미지에서 보이는 것처럼 root div외에 다른 태그는 없고 출력하는 문자열만 달랑 들어가 있죠.
이렇게 React.Fragment를 사용하게 되면, 최상위 요소에 자식 요소를 그대로 넣어버리는 효과가 있습니다. 그렇기 때문에 자식 요소를 여러 개 만들 때 이 Fragment를 활용한다는 사실을 알아두시면 좋습니다.
지금까지 예시들은 매우 간단한 Element들을 만들어내는 컴포넌트를 다루었습니다. 하지만 실제로는 저런 간단한 구조로 코드를 작성하지 않겠죠.
우리가 다음과 같은 Element 구조를 만든다고 가정해 봅시다.
<section>
<div>
<h1>Hello</h1>
<ul>
<li>React1</li>
<li>React2</li>
</ul>
</div>
</section>
태그들이 다양하게 중첩되었습니다. 이것도 컴포넌트를 만드는 방식으로 한번 도전해보죠.
ReactDOM.render(
React.createElement(
"section",
null,
React.createElement(
"div",
null,
React.createElement("h1", null, "Hello"),
React.createElement("ul",
null,
React.createElement("li", null, 'React1'),
React.createElement("li", null, 'React2'))
)),
document.querySelector('#root')
)
나름 구조가 복잡해졌기 때문에 위 쪽 html 구조 코드를 꼼꼼히 보면서 코드를 작성해보았습니다. 어떠신가요?
들여쓰기를 적용해서 나름 구조를 표현하려고도 했는데, 중첩된 코드가 너무 많아서 가독성이 정말 구립니다.
타인이 아니라 코드의 작성자인 제 자신도 나중에 보면 정신이 혼미해질 것 같은 코드입니다. 잘 작동하긴 하지만, 이런 식으로 코드를 짜다간 코딩에 정이 떨어져 버릴지도 모릅니다.
정말 다행스럽게도, 이런 코드를 방지하기 위해서 JSX라는 특수한 문법이 개발되었습니다. 다음 글에서는 위 예시같은 스파게티 코드를 JSX를 활용해서 어떻게 타개할 수 있을지 제대로 알아보겠습니다.