바벨 사용하지 않고 리액트 컴포넌트 만들어보기
JSX에서 map 메서드를 사용해 배열을 반환해야 하는지 궁금해서 글을 작성하게 됐다.
JSX에서 map 메서드를 왜 사용하는지 알아보기 전에 babel의 도움 없이 React 컴포넌트를 만들어보면서 babel이 해주는 역할에 대해 알아갈 필요가 있다.
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const List = (
<ul className="list" style={{ color: "blue" }}>
<li>React</li>
</ul>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(List);
</script>
</body>
babel을 사용하면 다음처럼 태그를 사용할 수 있는 자바스크립트 확장 문법이 사용 가능하고, 이를 사용하지 않는 경우는 아래처럼 작성해야 한다.
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
const List = React.createElement("ul", { className: "list", style: { color: "blue" } },
React.createElement("li", null, "React"),
);
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(List);
</script>
</body>
// 바벨을 사용한 경우
const List = (
<ul className="list" style={{ color: "blue" }}>
<li>React</li>
</ul>
);
// 바벨을 사용하지 않은 경우
const List = React.createElement("ul", { className: "list", style: { color: "blue" } },
React.createElement("li", null, "React"),
);
이렇게만 봐도 JSX를 사용하는 것이 더 가독성이 뛰어나고, 유지보수 면에서도 훨씬 좋은 것을 확인할 수 있다. 그리고 이러한 컴파일링을 도와주는 녀석이 바로 babel이다!
babel은 이렇게 JSX와 함께 최신 자바스크립트 기능을 활용하고 싶을 때 우리가 작성한 코드를 브라우저가 해석할 수 있는 코드로 변환해줄 수 있도록 도와준다. 그리고 예전에는 페이스북이 만든 JSX 변환기가 JSX를 처리하는 표준적인 방식이었지만 이제는 바벨이 JSX 처리 표준이다.
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
const List = React.createElement("ul", { className: "list", style: { color: "blue" } },
React.createElement("li", null, "React"),
React.createElement("li", null, "Vue"),
React.createElement("li", null, "Angular"),
);
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(List);
</script>
</body>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
const spa = ["React", "Vue", "Angular"];
const List = React.createElement("ul", { className: "list", style: { color: "blue" } },
// [
// React.createElement("li", { key: 0, onClick: () => alert("React") }, "React"),
// React.createElement("li", { key: 1, onClick: () => alert("Vue") }, "Vue"),
// React.createElement("li", { key: 2, onClick: () => alert("Angular") }, "Angular"),
// ]
spa.map((v, i) => React.createElement("li", { key: i, onClick: () => alert(v) }, v))
);
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(List);
</script>
</body>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const spa = ["React", "Vue", "Angular"];
function List() {
return (
<ul className="list" style={{ color: "blue" }}>
{spa.map((v, i) => (
<li key={i} onClick={() => alert(v)}>{v}</li>
))}
</ul>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(<List />);
</script>
</body>
그렇지 않다! children 프롭으로 아까 말했던 것처럼 세 번째 인자로 배열만 반환해준다면 reduce를 사용하든 forEach로 return하든 상관이 없다.
// spa.map((v, i) => React.createElement("li", { key: i, onChange: () => alert(v) }, v))
spa.reduce((arr, v, i) => [...arr, React.createElement("li", { key: i, onClick: () => alert(v) }, v)], [])
function List() {
return (
<ul className="list" style={{ color: "blue" }}>
{spa.reduce((arr, v, i) => (
[...arr, <li key={i} onClick={() => alert(v)}>{v}</li>]
), [])}
</ul>
);
}
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
const spa = ["React", "Vue", "Angular"];
function List({ children }) {
return React.createElement("ul", { className: "list" },
children
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(
React.createElement("ul", { className: "list" },
spa.map((v, i) => React.createElement("li", { key: i, onChange: () => alert(v) }, v)),
)
);
</script>
</body>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const spa = ["React", "Vue", "Angular"];
function List({ children }) {
return (
<ul className="list" style={{ color: "blue" }}>
{children}
</ul>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
// 렌더링 과정에서 리액트는 이 엘리먼트를 실제 DOM 엘리먼트로 변환한다.
root.render(
<List>
{spa.map((v, i) => (
<li key={i} onClick={() => alert(v)}>
{v}
</li>
))}
</List>
);
</script>
</body>