์ด๋ฒ ๊ธ์ ์น ์ปดํฌ๋ํธ ์๊ฐ ์ฐ์ฌ 5๋ฒ์งธ๋ก ์น ์ปดํฌ๋ํธ๋ฅผ react์ฒ๋ผ ์ฝ๋ฉํ๊ธฐ๋ฅผ ํด๋ณด๊ฒ ๋ค. ์ฌ์ฉํ๋ ์์ ์ ์ฒด ์ฝ๋๋ Todo Web Components์์ ์ฐธ์กฐํ ์ ์๋ค. ์ด ์์ ๋ฅผ ํตํด ์ง๋ ์ฐ์ฌ์์ ์์๋ณด์๋ ์ปค์คํ ์๋ฆฌ๋จผํธ, ์๋์ฐ ๋ ๊ทธ๋ฆฌ๊ณ lit-HTML์ ์ฌ์ฉํ์ฌ ์น ์ปดํฌ๋ํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๋ป๊ฒ ๋ง๋ค ์ ์๋์ง ํ์ธํด๋ณด์.
๊ธ์ ์ฝ๊ธฐ ์ ์ ์๋์ ๋งํฌ์์ ์์ ํ์ด์ง๋ฅผ ์ด์ด๋๊ณ ์์ํ์.
์ด๋ฒ ๊ธ์์ ์ฌ์ฉํ๋ Todo Web Components ์์ ๋ TodoMVC๋ฅผ ๋ฐ๋ผ ๋ง๋ค์๋ค. TodoMVC๋ ์ ๋ง์ ํ๋ก ํธ์๋ ํ๋ ์์ํฌ ์ค์ ์ ํ์ ํด์ผ ํ๋ ๊ฐ๋ฐ์๋ฅผ ๋๊ธฐ ์ํด ๋ง๋ค์ด์ก๋ค. ์ด๊ณณ์์ ๊ฐ์ TODO ์ฑ์ ๊ฐ ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํ์ฌ ์ด๋ป๊ฒ ๊ตฌํํ ์ ์๋์ง, ์์ ๋ค์ ํ์ธํ์ฌ ๋น๊ตํด ๋ณผ ์ ์๋ค. TodoMVC ์์ ๋ ์ด๋ ํ ํ๋ ์์ํฌ์ ๊ฐ์ ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ง๋์น๊ฒ ๊ฐ๋ตํ๋๊ณ ํธ์ค๋ ์์ ๊ฐ ์๋๋ผ, ์ด๋ ์ ๋ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ฑํ๋ ๊ฒ๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋์ด ์์ผ๋ฏ๋ก ๊ฐ๊ด์ ์ผ๋ก ๋น๊ตํด ๋ณผ ์ ์๋ ์ฅ์ ์ด ์๋ค. ์์ ์ด์ ๋ก ์์ ์ฝ๋๊ฐ ์ด๋ฒ ์ค๋ช ์์ ํ์ํ ๊ฒ๋ณด๋ค ๋ค์ ๊ธธ๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์ด๋ฒ ๊ธ์์๋ ์ ์ฒด ์ฝ๋๊ฐ ์๋ ์ผ๋ถ ์ฝ๋๋ค๋ง ๋ผ์ด ์ค๋ช ํ๋๋ก ํ๊ฒ ๋ค. ๋ํ, ์ด ์์ ๋ ์ค๋น๊ฐ ๋๋ฉด TodoMVC์ ์ ์ถํ ์์ ์ด๋ฏ๋ก, ์ฌ๋ฌ๋ถ์ด ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ๊ฒธํด์ฃผ์ด๋ ์ข๊ฒ ๋ค.
์ด ํ๋ก์ ํธ๋ ์ง๋ ์ฐ์ฌ์์ ์์๋ณด์๋ ์ปค์คํ ์๋ฆฌ๋จผํธ, ์๋์ฐ ๋ ๊ทธ๋ฆฌ๊ณ lit-HTML์ ์ฌ์ฉํ๊ณ ์๋ค. ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ES6 Class ๋ฌธ๋ฒ์ด ํ์์ด๋ค. ๋ ๋ง์ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ํ๊ธฐ ์ํด์ babel์ ํตํด ES5 ๋ฌธ๋ฒ์ผ๋ก src์ ์๋ ์์ค ํ์ผ๋ค์ ํธ๋์คํ์ผ๋ง ํ๋ฉฐ, ๊ทธ ํด๋ง์ webpack์ ํตํด dist์ ์ ์ฅํ๊ณ ์๋ค. ํ๋ก์ ํธ ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ๋ค.
src: ์์ค ํ์ผ๋ค
invalidate
๋ฅผ ํธ์ถํ๋ฉด ํ๋ฉด ์
๋ฐ์ดํธ๋ฅผ ์ค์ผ์ค์ด๋ฒ ๊ธ์ ๋ฐ๋ผ๊ฐ๋๋ฐ ๋ฐ๋์ ๋ก์ปฌ์์ ์ด ํ๋ก์ ํธ๋ฅผ ์คํํด์ผ ํ๋ ๊ฒ์ ์๋๋ฏ๋ก, ์์น ์๋ ๋ ์๋ ์ด ์น์ ์ ๋์ด๊ฐ๋ ๋ฌด๋ฐฉํ๋ค. ์์์ ์๋ ค์ค Todo Web Components ์ฑ ์ ์ฅ์์ ๋ฐ๋ชจ ํ์ด์ง๋ง ์ฐธ์กฐํด๋ ์ถฉ๋ถํ๋ค.
๋ก์ปฌ์์ ํ์ธํ๊ณ ์ ํ๋ค๋ฉด ์ฐ์ git ์ปค๋งจ๋๋ก Todo Web Components ์ฑ ์ ์ฅ์์์ ์ ์ฒด ํ๋ก์ ํธ๋ฅผ ๊ฐ์ ธ์ค์.
git clone git@github.com:kyuwoo-choi/todo-web-components.git
๊ทธ๋ค์ yarn
์ปค๋งจ๋๋ก ํ์ํ ๋ํ๋์ ํจํค์ง๋ค์ ์ค์นํ๋ค. yarn
์ด ์ค์น๋์ด ์์ง ์๋ค๋ฉด ๋ฌผ๋ก npm
์ ์ฌ์ฉํ์ฌ๋ ๋ฌด๋ฐฉํ๋ค.
yarn install
ํน์
npm install
์ด์ ํ์ํ ์ค๋น๊ฐ ๋๋ฌ์ผ๋ฏ๋ก package.json์ ์ ์๋ serve
์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ฌ ๋ธ๋ผ์ฐ์ ๋ก ํ์ธํด๋ณด์. http://localhost:8080/
yarn run serve
ํน์
npm run serve
<html>
<head>
...
<script
src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.20/custom-elements-es5-adapter.js"
defer
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.20/webcomponents-sd-ce.js"
defer
></script>
<script src="./dist/TodoApp.js" defer></script>
...
</head>
</html>
<head>
์๋ ํธ๋์คํ์ผ ๋ TodoApp.jsํ์ผ ๊ทธ๋ฆฌ๊ณ ๋ ๊ฐ์ ์น ์ปดํฌ๋ํธ ํด๋ฆฌํ custom-elements-es5-adapter.js, webcomponents-sd-ce.js ์คํฌ๋ฆฝํธ๊ฐ ํฌํจ๋์๋ค.
ํ์ฌ ํฌ๋กฌ๊ณผ ์ฌํ๋ฆฌ ๋ธ๋ผ์ฐ์ ์์๋ ํด๋ฆฌํ ์์ด ํ์ธํ ์ ์์ผ๋ฉฐ, ๋ ํด๋ฆฌํ์ ์ฌ์ฉํ๋ฉด ํ์ด์ดํญ์ค, ์ฃ์ง, IE11๋ ์ง์ํ ์ ์๋ค.
์น ์ปดํฌ๋ํธ ํด๋ฆฌํ ์ค ์ด ํ๋ก์ ํธ์์๋ Shadow DOM, Custom Elements๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, webcomponents-sd-ce.js๋ฅผ ์ ํํ๋ค. (ํด๋ฆฌํ ํ์ผ ์ด๋ฆ์ ํฌํจ๋ sd
, ce
๋ Shadow DOM
, Custom Elements
์ ์ฝ์์ด๋ค)
๋ํ ์ปค์คํ
์๋ฆฌ๋จผํธ๊ฐ ํ์๋ก ํ๋ ES6๋ฌธ๋ฒ์ ES5๋ฌธ๋ฒ์ผ๋ก ํธ๋์คํ์ผํ๊ณ ์์ผ๋ฏ๋ก custom-elements-es5-adapter.js๊ฐ ํ์ํ๋ค.
<body>
<todo-app></todo-app>
...
</body>
</html>
<body>
๋ ๊ฐ๋ตํ <todo-app>
ํ๊ทธ๋ฅผ ํฌํจํ๊ณ ์๋ค. ์ด ํ๊ทธ๋ TodoApp.js์ ํฌํจ๋ ์ปค์คํ
์๋ฆฌ๋จผํธ๊ฐ ์ ์ํ๊ณ ์๋ค.
์ด์ฒ๋ผ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ๋ ์
์ฅ์์๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ๊ณผ ํ๊ทธ๋ฅผ ํ๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ฟ์ผ๋ก ๋งค์ฐ ํธ๋ฆฌํ๋ค.
todoApp.js๋ src/components์์ ์ฐพ์ ์ ์์ผ๋ฉฐ, ์ index.html์์ ์ฌ์ฉํ <todo-app>
ํ๊ทธ๋ฅผ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ก ์ ์ํ๋ค.
๋๋ถ์ด ํ๋์ ์ ํ๋ฆฌ์ผ์ด์
์ผ๋ก์ ํ์ํ API๋ ์ ๊ณตํ๊ณ ์๋ค.
import { html } from "lit-html";
import LitRender from "../libs/litRender";
import store from "../libs/store";
import {
add,
toggle,
remove,
toggleAll,
clearCompleted,
replace
} from "../libs/actions";
import "./todoInput";
import "./todoToolbar";
import "./todoList";
์ฝ๋ ์๋จ์์ ํ์ํ ๋ํ๋์๋ค์ ๊ฐ์ ธ์จ๋ค. html๋ ๋๋ง์ ํ์ํ lit-HTML๊ณผ ์ด๊ฒ์ ์ปค์คํ
์๋ฆฌ๋จผํธ์์ ํธํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด ์ ์ํ LitRender
๋ฏน์ค์ธ ํฌํผ.
์ ํ๋ฆฌ์ผ์ด์
์ํ์ ์ก์
์ ๊ด๋ฆฌํ๊ธฐ ์ํ Redux-Zero(Redux ๋ฏธ๋๋ฏธ๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค) store
์ add
, toggle
๊ฐ์ ์ก์
๋ค.
๋ง์ง๋ง์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์
์ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ฑํ๋ todoInput
, todoToolbar
, todoList
๋ฅผ ๊ฐ์ ธ์จ๋ค.
import './todoInput'
์ ๋ฌธ๋ฒ์ด ์๋ฌธ์ค๋ฌ์ด ๋
์๋ ์์ ๊ฒ์ด๋ผ ๋ณธ๋ค. ์ด๊ฒ์ ๊ฐ์ ธ์จ ๋ชจ๋์ ์ ์ฅํ์ง ์๊ณ ๋ชจ๋์ ๋ก๋๋ง ์ํ ๋ฐฉ๋ฒ์ด๋ค.
import TodoInput from './todoInput'
๋ ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ๋ฒ์ด์ง๋ง, ์ฝ๋์์ TodoInput
์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ ์นํฉ์ด Tree Shaking์ผ๋ก ๋ํ๋์๋ฅผ ์ ๊ฑฐํด ๋ฒ๋ฆฐ๋ค.
์ด๋ฅผ ํผํ๊ธฐ ์ํ ๋ฌธ๋ฒ์ด๋ฉฐ, ๋ฑํ ์ปดํฌ๋ํธ ํด๋์ค๋ค์ ์ง์ ์ฌ์ฉํ์ง๋ ์์ผ๋ฏ๋ก ํ์ฌ์ ํํ๊ฐ ๋์๋ค๊ณ ์ดํดํ๋ฉด ๋๊ฒ ๋ค.
...
class TodoApp extends LitRender(HTMLElement) {
constructor(name) {
super();
this.attachShadow({ mode: 'open' });
this.invalidate();
}
...
ES6 class๋ฌธ๋ฒ์ผ๋ก TodoApp
์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ ์ํ๋ค. ์ด ํด๋์ค๋ HTMLElement
๊ณผ LitRender
๋ฏน์ค์ธ์ ํ์ฅํ๋ค.
constructor
์์๋ ์๋์ฐ ๋์ open
๋ชจ๋๋ก ์ด ์ปค์คํ
์๋ฆฌ๋จผํธ์ ์์ฑํ๋ค.
๋ง์ง๋ง์ผ๋ก invalidate()
๋ฅผ ํ๊ณ ์๋๋ฐ, ์ด๋ LitRender
์ ์ ์๋ ํจ์๋ก ์ด ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง ํ๋๋ก ํด์ค๋ค.
LitRender
์ invalidate
์ ๋ํด์๋ ์ดํ ๋ ์์ธํ ์์๋ณด๊ณ , ์ฌ๊ธฐ์๋ ์ง๊ด์ ์ผ๋ก invalidate
์ ํจ์ฉ๋ง ๋ ์ฌ๋ฆฌ๋ฉด ์ถฉ๋ถํ๋ค.
...
add(title) {
add(title);
}
...
get length() {
const todoList = store.getState().todoList;
return todoList.length;
}
...
API๋ฅผ ์ ์ํ๋ค. ๋ฐ๋ชจ ํ์ด์ง ํน์ ๋ก์ปฌ ์๋ฒ http://localhost:8080์ ์ ์ํด์ API๋ฅผ ์ฌ์ฉํด๋ณด์.
document.querySelector('todo-app').add('hello')
, document.querySelector('todo-app').length
์ ์ปค๋งจ๋๋ก ์ฌ์ฉํ ์ ์๋ค.
ํธํ์ง ์์๊ฐ?! ์ฐ๋ฆฌ๋ ์ปค์คํ
์๋ฆฌ๋จผํธ ํด๋์ค์ ํจ์๋ฅผ ์ ์ํด ์ฃผ๋ ๊ฒ์ผ๋ก ์ด์ฒ๋ผ ์ง๊ด์ ์ธ API๋ฅผ ์ ๊ณตํด ์ค ์ ์๋ค.
...
render() {
return html`
<style>
host: {
display: block;
}
section {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
</style>
<section>
<todo-input></todo-input>
<todo-list></todo-list>
<todo-toolbar></todo-toolbar>
</section>
`;
}
}
...
render
ํจ์๋ ์์ invalidate
์ ์์ ์ด๋ฃจ๋ ํจ์๋ก LitRender
๋ฅผ ํตํด ํธ์ถ๋๋ค.
์ด ํจ์๊ฐ ํธ์ถ๋๋ฉด lit-HTML์ html
Template Literal ํจ์๋ฅผ ์ฌ์ฉํด ์ด ์ปค์คํ
์๋ฆฌ๋จผํธ์ ํ์ ์๋ฆฌ๋จผํธ๋ฅผ ๋ ๋๋งํ๋ค.
์ค์ค! ์ ๋ฒ React ๊ฐ์ ๋ชจ์์๊ฐ ๋์์ง ์์๊ฐ?
customElements.define("todo-app", TodoApp);
๋ง์ง๋ง์ผ๋ก ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ ์ํ ํด๋์ค๋ฅผ todo-app
ํ๊ทธ๋ก ์ ์ํ๋ค.
์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์์ฑํ ๋ todo-app
์ฒ๋ผ ํ๊ทธ ์ด๋ฆ์ ๋ฐ๋์ -
๋ฅผ ํ๋ ์ด์ ํฌํจํด์ผ ํจ์ ๊ธฐ์ตํ์.
๋ธ๋ผ์ฐ์ ๋ HTML์ ํ์ฑํ๋ค -
๋ฅผ ํฌํจํ ํ๊ทธ๋ฅผ ๋ง๋๋ฉด ์ด๊ฒ์ด ์ปค์คํ
์๋ฆฌ๋จผํธ๋ก ์ฐ์ผ ์ ์๋ค๋ ๊ฒ์ ์์์ฑ ์ฒ๋ฆฌํ ์ ์๋ค.
litRender.js๋ src/libs ๋ฐ์์ ์ฐพ์ ์ ์์ผ๋ฉฐ, ์ด ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ ์ปดํฌ๋ํธ๋ค์ ๋ ๋๋ง์ ๋๋๋ค.
๊ฐ ์ปดํฌ๋ํธ๋ค์ class SomeComponent extends LitRender(HTMLElement)
์ ํ์์ผ๋ก litRender
๋ฅผ ๋ฏน์ค์ธ ํ์ฅํ์ฌ ์ฌ์ฉํ๋ค.
ํ๋ฒ์ ์ฌ๋ฌ๋ฒ ๋ด์ฉ์ด ์
๋ฐ์ดํธ๋๋ ๊ฒฝ์ฐ ๋งค๋ฒ ๋ ๋๋ง ํ์ง ์๊ณ , ๋ชจ์๋ค๊ฐ ํ๋ฒ์ ๋ ๋๋ง ํ๋ ๊ฒ์ผ๋ก ์ฑ๋ฅ ํฅ์์ ๋์ ์ฃผ๊ธฐ ์ํ ์ฝ๋์ด๋ค.
์ด๊ฒ์ ํ์ฅํ๋ ์ปดํฌ๋ํธ์์ this.invalidate
๋ฅผ ํธ์ถํ๋ฉด ์ปดํฌ๋ํธ์ ์ ์๋ render
ํจ์์ ํธ์ถ์ด ์์ฝ๋๋ค.
import { render } from "../../node_modules/lit-html/lib/lit-extended";
export default base =>
class extends base {
render() {}
async invalidate(instant) {
if (!this.needsRender) {
if (!instant) {
this.needsRender = true;
await 0;
this.needsRender = false;
}
render(this.render(), this.shadowRoot);
}
}
};
Todo ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ฑํ๋ ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ค์ ์ ์ํ๋ค. todoApp.js ์ฝ๋๋ฅผ ๋ณด๋ฉด <todo-list>
, <todo-toolbar>
๋ฑ์ ํํ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
import { toggle, remove, replace } from '../libs/actions';
...
class TodoItem extends LitRender(HTMLElement) {
...
connectedCallback() {
const root = this.shadowRoot;
...
root.addEventListener('click', handlers.onClick);
...
}
disconnectedCallback() {
const root = this.shadowRoot;
...
root.removeEventListener('click', this._handlers.onClick);
...
}
...
_onClick(event) {
const id = this.todo.id;
const classList = event.path[0].classList;
if (classList.contains('toggle')) {
toggle(id);
} else if (classList.contains('destroy')) {
remove(id);
}
}
...
TodoApp
์์๋ ์ฌ์ฉ๋์ง ์์๋ connectedCallback
, disconnectedCallback
์ด ๋ณด์ธ๋ค.
์ด ํจ์๋ค์ ์ปค์คํ
์๋ฆฌ๋จผํธ ์ฝ๋ฐฑ์ผ๋ก ์ด ์๋ฆฌ๋จผํธ๊ฐ DOM์ attach, detach๋ ๋ ํธ์ถ๋๋ค.
๋ฐ๋ผ์ ์ด ์ฝ๋ฐฑ ํจ์๋ค์ด DOM ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํ ๋น/ํด์ ํ๋๋ฐ ์ต์ ์ ์ฅ์์ด๋ค.
๋ง์ฝ ์ ์ ํ ํธ๋ค๋ฌ๋ฅผ ํด์ ํด์ฃผ์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๊ฒฝํํ ์ ์์ผ๋ ์์ง ๋ง์.
onClick
ํธ๋ค๋ฌ๋ ์กฐ๊ฑด์ ๋ฐ๋ผ toggle
, remove
Redux ์ก์
์ ์ํํ๊ณ ์๋ค.
render() {
const todo = this.todo;
const classCompleted = todo.completed ? ' completed' : '';
const inputToggle = todo.completed
? html`<input class="toggle" type="checkbox" checked>`
: html`<input class="toggle" type="checkbox">`;
const classEditing = this._editing ? ' editing' : '';
return html`
${style}
<div data-id$="${todo.id}" class$="${'item' +
classCompleted +
classEditing}">
<div class="view">
${inputToggle}
<label>${todo.title}</label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" />
</div>
`;
}
}
...
const style = html`
<style>
host: {
display: block;
}
.item {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
...
</style>
`;
...
render
ํจ์๊ฐ ์กฐ๊ธ ๋ณต์ก์ก๋ค. lit-HTML html
ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด ํจ์๋ ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด์ ์ธ์๋ก ๋ฐ์ HTMLTemplateElement๋ฅผ ํฌํจํ๋ ์ค๋ธ์ ํธ TemplateResult๋ฅผ ๋ฐํํ๋ค.
${something}
์๋ ๋ณ์๋ ์์ํํ ์ด์ธ์๋ TemplateResult, Promise, Array, Iterables ๋ฑ์ ์ง์ํ๋ค.
์ฌ๋ฌ ๋ฐฉ์์ ์กฐํฉํ์ฌ ์์ ๋กญ๊ฒ ํ
ํ๋ฆฟ์ ๊ตฌ์ฑํ๋ฉด ๋๋ค.
์์ ์ฝ๋์์๋ ํ
ํ๋ฆฟ์ด ๋ณต์กํด ๋ณด์ด์ง ์๊ฒ <style>
, <input>
๋ฑ์ ๋ถ๋ฆฌํ ํ, html
ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด์ ์ค๋ณตํ์ฌ ์ฌ์ฉํ๊ณ ์๋ค.
// todoList.js
render() {
...
const todoItems = todoList
.filter(todo => {
return (
route === '' ||
(route === 'completed' && todo.completed) ||
(route === 'active' && !todo.completed)
);
})
.map(todo => html`<todo-item todo=${todo}></todo-item>`);
return html`
${style}
<div class="todo">
${btnToggleAll}
<div class="todo-list">
${todoItems}
</div>
</div>
`;
}
...
// todoItem.js
set todo(todo) {
this._todo = todo;
this.invalidate();
}
lit-HTML์ ํ์ฅ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด html`<todo-item todo=${todo}></todo-item>`
์ฒ๋ผ ๋ค๋ฅธ ์ปค์คํ
์๋ฆฌ๋จผํธ์ object
๋ฅผ ์ ๋ฌํ ์ ์๋ค.
Attribute๋ html`<todo-item name$=${someText}></todo-item>`
๋ก ์ด๋ฆ ๋ค์ $
๋ฅผ ๋ถ์ด๋ฉด ๋๋ค.
๋ฐ์์ค๋ object
๋ฅผ ์ฌ์ฉํ๋ todoItems.js์์๋ ํ๋ฒํ๊ฒ this.todo
๋ก ์ ๊ทผํ๋ฉด ๋๋ค.
์ด ์ฝ๋์์๋ getter๋ฅผ ๋ง๋ค์ด์ ๊ฐ์ด ํ ๋น๋๋ฉด ์๋์ผ๋ก invalidate
๋ฅผ ํธ์ถํ์ฌ ์ปค์คํ
์๋ฆฌ๋จผํธ๊ฐ ์
๋ฐ์ดํธ ๋๋๋ก ํ๋ค.
์ฌ๊ธฐ์ ํ๊ฐ์ง ์ง๊ณ ๋์ด๊ฐ ์ ์ lit-HTML์ ์๋๋ฐฉ์์ด ์ถฉ๋ถํ ์ฑ๋ฅ์ ๊ณ ๋ คํด ๋ง๋ค์ด ์ก๋ค๋ ๊ฒ์ด๋ค.
์ด๊ฒ์ ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด๋ก ์ ๋ฌ๋ ๊ฐ์ ๊ธฐ์ตํ๊ณ ์๋ค๊ฐ, ์ ๋ฌ๋ ๊ฐ์ด ๋ค๋ฅผ ๊ฒฝ์ฐ์๋ง ์ปดํฌ๋ํธ๋ฅผ ์
๋ฐ์ดํธํ๋ค.
๋ฐ๋ชจ์์ ์ด ์ฝ๋๊ฐ ๋์ํ๋ ๊ฒ์ ํ์ธํด๋ณด๋ฉด ์ถ๊ฐ/์ญ์ /๋ณ๊ฒฝ๋ ์์ดํ
๋ง ์
๋ฐ์ดํธ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Redux-Zero์ store, action๋ค์ ์ ์ํ๋ค. ์ฌ๋ฌ๋ถ๊ป ์ด๋ฏธ ์ต์ํ Redux๊ฐ ๊ฐ๋ตํด์ง ๋ชจ์์ด๋ฉฐ, ์น ์ปดํฌ๋ํธ ์ค๋ช ๊ธ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ฏ๋ก ์ด ๋ถ๋ถ์ ์ค๋ช ์ ์๋ตํ๊ฒ ๋ค.
import createStore from "redux-zero";
const initialState = { route: "", todoList: [] };
const store = createStore(initialState);
export default store;
import store from './store';
function actionCreator(action) {
return function() {
let state = store.getState();
state = action(state, ...arguments);
store.setState(state);
};
}
...
export const remove = actionCreator((state, id) => {
state.todoList = state.todoList.filter(todo => todo.id !== id);
return state;
});
...
์ฌ๊ธฐ๊น์ง TODO ์ ํ๋ฆฌ์ผ์ด์ ์ ์ปค์คํ ์๋ฆฌ๋จผํธ, ์๋์ฐ ๋๊ณผ lit-HTML์ ์ฌ์ฉํ์ฌ ์ฐ๋ฆฌ์๊ฒ ์ต์ํ React์ฒ๋ผ ์์ฑํ ์ฝ๋๋ฅผ ๊ฐ๋ณ๊ฒ ์ค๋ช ํ๋ค. ์ด ๋ฐฉ๋ฒ์ ๋จ์ํ React๋ฅผ ํ๋ด ๋ด๋ ๊ฒ์ด ๋ชฉ์ ์ด ์๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ฐ๋ฆฌ์๊ฒ ์ต์ํ ๋ฐฉ๋ฒ์ผ๋ก ์ ๊ทผํ ์ ์์ผ๋ฉด์๋, ํ๋ ์์ํฌ๋ฅผ ์๊ตฌํ์ง ์๋๋ค. ๋จ์ง 2kb๊ฐ ์ฑ ์๋๋ lit-HTML ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ํ๋ ์ฌ์ฉํ๊ณ ์๋ค. ์ด๊ฒ์ด ์ฐ๋ฆฌ์๊ฒ ์ฃผ๋ ์ฅ์ ์ ๋๋ ทํ๋ค.
document.querySelector('todo-app').add('hello')
๊ฐ์ ์ง๊ด์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํด์ฃผ๋ ํ๋ ์์ํฌ๋ ์๋ค.์ด ๊ฐ์ ์ฅ์ ์ ์ด๋๋ ค ์ด ์ฐ์ฌ๊ธ์ ๋ฒ์จ 5๋ฒ์งธ ์ฐ๊ณ ์๋ค. ๋ฌผ๋ก ํ๋ ์์ํฌ๊ฐ ์ ๊ณตํด์ฃผ๋ ํธ๋ฆฌํจ์ด๋, ๋ธ๋ผ์ฐ์ ์ง์ ๋ฑ์ ์๊ฐํด๋ณด๋ฉด ์์ฌ์ด ์ ๋ค์ด ์์ง ์๋ค. lit-HTML ์ญ์ ์กฐ๊ธ ๋ ๋ค๋ฌ์ด์ ธ์ผ ํ ํ์๊ฐ ์๋ค. ์ด ์์ ๋ํ lit-HTML์ด ์ ๋ฆฌ๋์ด ์ด ์์ ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ค. ๊ทธ๋ฌ๋ ์ด ์ฅ์ ๋ค์ ์ถฉ๋ถํ ์ด๋ฆฐ๋ค๋ฉด, ์ ๋นํ ์๊ธฐ(์๋ง๋ IE10 ์ดํ๋ฅผ ์ง์ด๋์ ธ๋ ๋๋ ๋)์, ๊ณตํต ์ปดํฌ๋ํธ๋ ์คํ์์ค๋ฅผ ๊ฐ๋ฐํ๋ ๊ณณ์์๋ ์ถฉ๋ถํ ๊ทธ ์ฅ์ ์ ๋ฐํํ ์ ์์ ๋๊ฐ ์ค๋ฆฌ๋ผ ๋ฏฟ๋๋ค.
Chrome Dev Summit 2017 - lit-HTML ์์์ ๋ณธ ํ, ์ฌ๊ธฐ์ ์๊ฐ๋ ๋๋ก lit-HTML ๊ทธ๋ฆฌ๊ณ , ์น ์ปดํฌ๋ํธ ์์ฒด๊ฐ ์ผ๋ง๋ ๋น ๋ฅธ ์ฑ๋ฅ์ ๋ณด์ฌ์ค ์ง ๊ถ๊ธํ๋ค. ๊ธฐ์์ด๋ฉด ์ด์ ๊ธ์์ ์ฝ์ํ ๋๋ก ์์ ๋ ๋ง๋ค์ด์ผ ํ๋ todo preact benchmark์ ์ถ๊ฐํ์ฌ ์ฑ๋ฅ ๋น๊ต๋ฅผ ํด๋ณด๋ ค ํ๋ค. ํ ์คํธ ๊ฒฐ๊ณผ๋ ๋๋ฌด ๋น ๋ฅด๋ค. ๋ค๋ง ๋๋ฌด ๋นจ๋ผ ์ค์ค๋ก ์๋ฌธ์ด ์๊ฒจ ์กฐ๊ธ ๋ ์์๋ณธ ๊ฒฐ๊ณผ, Vue.js TodoMVC Benchmark๋ฅผ ์ฐพ์๋ค. ํ์ ์ญ์ ์ด ์๊ฒฌ์ฒ๋ผ ํ๋ ์์ํฌ ๋ฒค์น๋งํฌ๊ฐ ์๋ฏธ ์๋ค๋ ๊ฒ์ ๋์ํ๊ธฐ ๋๋ฌธ์ ๋ฒค์น๋งํฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ก ๋ง๋ค์ง๋ ์์๊ณ , ์ด ํ๋ก์ ํธ๋ง TodoMVC์ ์ ์ถํ ์์ ์ด๋ค. ๊ทธ๋ฌ๋ ํ์ค ์คํฌ๋ฆฝํธ๋ง์ผ๋ก ๋์ํ๋ ์ด ๋ฐฉ์์ด ์ถฉ๋ถํ ๋น ๋ฅผ์ ๋ฐ์ ์๋ค๋ ๊ฒ์ ๋ ์ ์ฌ๋ฌ๋ถ๋ค๋ ์ ์์๋ฆฌ๋ผ ์๊ฐํ๋ค. ๊ฐ์ธ์ ์ผ๋ก #UseThePlatform์ ๊ฐ์น, ์น ์ปดํฌ๋ํธ์ ๋น์ ์ ๊ฑฐ๋ ๊ธฐ๋๊ฐ ํฌ๊ธฐ์ ์ด ๊ธ์ ์ฝ๋ ๋ ์๊ฐ ํ๋ช ์ด๋ผ๋ ๋ ๋์ํด์ ์ฃผ๋ณ์ ์น ์ปดํฌ๋ํธ ๊ฐ๋ฐ์ ํ๋ ํ๊ฒฝ์ ๋ณผ ์ ์์ผ๋ฉด ์ข๊ฒ ๋ค๋ ๋ฐ๋์ด๋ค. ์ด ๊ธ์ ๋์ผ๋ก ์น ์ปดํฌ๋ํธ ์ฐ์ฌ๋ฅผ ๋ง์น๋ค.