[리액트] jsx 없이 js 만으로 html 작성하기
August 30, 2020 - [react, react-hyperscript, jsx]
리액트에서 JSX 는 컴포넌트가 렌더링하는 dom 구조를 정의할 때 사용된다. 순수 JS에서 html 을 마크업하는 것은 여간 귀찮 일이 아니기 때문에 JSX 는 리액트에서 정말 유용하다.
필자는 개인적으로 XML(HTML) 문법을 선호하지 않는데, 이는 XML 문법이 너무나 verbose 하게 느껴지기 때문이다. 특별히 매번 닫는 태그를 마지막에 빠짐없이 넣어줘야 하는 모양이 늘 마음 한켠을 무겁게 한다.
나와 같은 minimalist 에게 좋은 대안이 있어 소개하고자 한다. 바로 react-hyperscript !
TMI)
react-hyperscript
는 리액트 공식문서에서도 소개되고 있다. https://reactjs.org/docs/react-without-jsx.html
우선 일반적으로 사용되는 JSX를 이용한 마크업을 보자
import React from 'react'
import AnotherComponent from './another-component'
export default () => (
<div className='.example'>
<h1 id="heading">This is hyperscript</h1>
<h2>creating React.js markup</h2>
<AnotherComponent foo="bar">
<li>
<a href={'http://whatever.com'}>One list item</a>
</li>
<li>
Another list item
</li>
</AnotherComponent>
</div>
)
react-hyperscript 를 이용하면 아래와 같이 dom 을 정의할 수 있다.
import h from 'react-hyperscript'
import AnotherComponent from './another-component'
export default () =>
h('div.example', [
h('h1#heading', 'This is hyperscript'),
h('h2', 'creating React.js markup'),
h(AnotherComponent, { foo: 'bar' }, [
h('li', [h('a', { href: 'http://whatever.com' }, 'One list item')]),
h('li', 'Another list item'),
]),
])
훨씬 간결하지 않은가!
눈치가 빠른 독자라면 h
함수가 React.createElement
와 뭐가 다른가 의문이 들 수도 있다. 단지 함수를 간단한 변수명에 담은 것에 지나지 않은가 생각할 수 있다. const h = React.createElement
와 같이 말이다. 하지만 여기에는 중요한 차이가 있다.
- 우선 첫번째 인자를 이용해 태그와 실렉터를 함께 정의할 수 있게 해준다는 것.
-
React.createElement
는 인자의 순서가 매우 중요하지만.react-hyperscript
는 인자의 타입에 따라 유연하게 attr 과 children 을 전달할 수 있다는 것- 첫번째 인자는 반드시 type 이 오게 될 것이고, 두번째 인자가
{}
와 같은 객체일 경우에는 attr 로 인식되며[]
와 같은 배열이나 단순 문자열인 경우에는 children 으로 처리가 됨 React.createElement
는 attr 없이 children 만 전달하려면 두번째 인자로 반드시null
을 명시해야 하는 불편함이 있지만,react-hyperscript
는 attr 을 생략하고 두번째 인자로서 바로 children 을 직접 전달할 수가 있다.
- 첫번째 인자는 반드시 type 이 오게 될 것이고, 두번째 인자가
더 나아가 hyperscript-helpers 와 함께 사용하면 아래와 같이 보다 가독성 높은 마크업이 가능하다.
import h from 'react-hyperscript'
import helper from 'hyperscript-helpers'
import AnotherComponent from './another-component'
const {div, h1, h2, li, a} = helper(h)
export default () =>
div('.example', [
h1('#heading', 'This is hyperscript'),
h2('creating React.js markup'),
h(AnotherComponent, { foo: 'bar' }, [
li(a({ href: 'http://whatever.com' }, 'One list item')),
li('Another list item'),
]),
])
hyperscript-helpers
팁
-
태그명 함수의 첫번째 인자로 주어지는 값이 문자열일 경우
.
으로 시작하면 클래스명,#
으로 시작하는 문자열은 아이디가 된다- 두번째 세번째 인자 없이, 첫번째 인자가
.
or#
으로 시작하지 않는 문자열일 경우 children 이 된다 .
or#
으로 시작되지 않는 문자열이 첫번째 인자이고, 두번째 인자가 문자열인 경우 첫번째 인자는 무시되고 두번째 문자열 인자가 children 이 된다.
- 여러 개의 children 은 배열(
[]
)로 묶는다. - 이런 특성 말고도 아무튼 전달되는 인자들을 알아서 적절하게 type, attr, children 값으로 사용해 준다.