lit-htmlをTODO Exampleを通して紹介する

どうも、ヒロと申します。フロントエンドマンです。
Polymer Advent Calendar 2017 7日目の担当です！
投稿が遅れてしまいすみません、、、汗

今回は[lit-html](https://github.com/PolymerLabs/lit-html)の紹介をしたいと思います。

lit-htmlとは[Polymerチーム](https://www.polymer-project.org/) が開発しているView用のライブラリです。
非常に軽量でシンプルなAPIのみ提供しているライブラリです。まだ絶賛開発中なのでプロダクション利用には向いていないと思いますが、今回はこのライブラリについて説明します。

いきなりですが、今回このようなサンプルを用意しました。

![for_lit_html.png](https://qiita-image-store.s3.amazonaws.com/0/79274/5f1bd20c-c55d-87e0-4875-947a96a7e8be.png)

はい、TODO Exampleです。
コードは[こちら](https://github.com/takahiro-saeki/lit-html-example)にあります。

では早速コードの説明に入る前に簡単にlit-htmlの使い方の説明！

lit-htmlの主要な機能は二つ、
- html()
- render()
の二つです。公式のサンプルそのままですが、

```js+jinja

import {html, render} from 'lit-html';

// html()関数でレンダリングするDOMの内容を定義します。
const helloTemplate = (name) => html`<div>Hello ${name}!</div>`;

// 引数に渡したパラメーターはそのまま${} 
// 内に渡ります。またレンダリングする時はrender() 関数の第一引数にhtml()で定義した
// 関数と第二引数にDOMを指定します。
render(helloTemplate('Steve'), document.body);

// 引数を変えて再度レンダリングすると引数の内容だけ再レンダリングされます。
render(helloTemplate('Kevin'), document.body);

```

ではここからサンプルのコードをざっくり解説したいと思います！

主なフォルダ構成

```
├── src
│   ├── index.ejs
│   └── js
│       ├── Todo.js
│       ├── components
│       │   ├── Footer.js
│       │   ├── FooterItem.js
│       │   ├── Header.js
│       │   ├── MainField.js
│       │   └── TodoItem.js
│       ├── containers
│       │   └── App.js
│       ├── domain
│       │   ├── allCheck.js
│       │   ├── check.js
│       │   ├── count.js
│       │   ├── deleteChild.js
│       │   └── filterChange.js
│       ├── index.js
│       ├── mock
│       │   ├── defaultFilter.js
│       │   └── mock.js
│       └── style.css
```
**Todo.js**
基本的な処理の内容を記述しているファイル
**components**
コンポーネント用のディレクトリ
**containers**
TODO周りの全体のUI用のディレクトリ
**domain**
components内のコンポーネント内で主に`on-click`内で発火する関数用のディレクトリ
**index.js**
custom-elementsのdefineをしているファイル
**mock**
初期状態のTodoデータと初期状態のフィルターのデータ等が記述されているファイルのあるディレクトリ
**style.css**
style.css

## 設計内容
主な処理は `Todo.js` 内に記述しているので、その中身を説明します。
主に `static get observedAttributes()` 内でobserveしている値によって `class` 内のメソッドを発火しています。

```js+jinja:src/Todo.js
...
  static get observedAttributes() {
    return ['update', 'delete', 'change', 'filter', 'all-check', 'init'];
  }

  attributeChangedCallback(name, oldValue, newValue) {
    switch (name) {
      case 'change':
        return this.change(newValue);
      case 'update':
        return this.update();
      case 'delete':
        return this.delete(newValue);
      case 'filter':
        return this.filterState(newValue);
      case 'all-check':
        return this.allCheckState();
      case 'init':
        return this.init(newValue);
    }
  }
...
```

また `this.generate(todoのデータが入っている配列, filterのデータが入っている配列)` という形で形で使用していて、TODOのデータを追加する時、削除する時等、何か変更が入る度にこのmethodを呼び出しています。

TODOのデータに関して `this.state` 内に値を保持しており、 `this.setState(stateをアップデートobject)` 関数を発火することでのみ内容を変えています。

また初期ロード時に、session storageに値があればその内容をレンダリングするという `this.read()` メソッドと、 何かしらの変更があったら現在の状態を保存する `this.store()` というメソッドがあります。
`this.read()` に関しては初期ロード時にのみ発火し、 `this.store()` に関しては各メソッドの最後の処理に発火し、状態を保存しています。

## 実装していて困った点
`lit-html` ではコンポーネント内で `onclick` を発火させる時に `on-click` と記述して使用します。 またコンポーネント内の `on-click` で埋め込んだ関数を発火すると `this.setAttribute()` でcustom-elementsの親階層のdata属性を変更して、その後に `static get observedAttributes()` でobserveしているdata属性に応じて `attributeChangedCallback()` 内で処理をしています。ただ、 `this.querySelector()` で親のcustom-elementを探してそのdata属性を変更するというのは綺麗な実装ではありません。
この辺りをもう少し工夫したかったなと思いました(時間があまりなかったというのはありますが、、、)

また `lit-html` 内の　APIが途中で変わったり、変更されたりしていたので、本当に絶賛実装中なんだなと感じました。特に `lit-extended.ts` 周りが特にですね。
というのも最初 `on-click` でコンポーネントに `onclick` イベントを埋め込むには `node_modules` 直下から以下のように
`./node_modules/lit-html/lib/lit-extended.ts` のように直接読み込まないと使用できませんでした。 ただバージョンアップに伴い、直接 `on-click` を書いても `onclick` イベントを発火出来るようになったのかもしれません。

## 終わりに
`lit-html` の紹介というよりかはサンプルを作ったのでその紹介みたいな感じになってしまいました。次回はちゃんとAPIの紹介をして行ければと思います。

個人的な意見ですが、　`lit-html` は今後どんどん改修、機能追加されて行くと思いますし、polymer 3.0と上手く組み合わせいけるような感じになるんじゃないかなーと思います。実際どうなんでしょう？引き続き動向を伺いつつ、深く理解していきたい次第です。

明日は[@howking](https://qiita.com/howking)さんの
[Polymer & Firebase でサイト更新したらプッシュ通知](https://qiita.com/howking/items/929674f9d9661df7de9e)です！

:christmas_tree: [Polymer Advent Calendar 2017](https://qiita.com/advent-calendar/2017/polymer)
:arrow_left: 6日目 [未経験者が触るPolymer 3.0 preview](https://qiita.com/usagi-f/items/0f0cde47c0a922412043) @usagi-f
:arrow_right: 8日目 [Polymer & Firebase でサイト更新したらプッシュ通知](https://qiita.com/howking/items/929674f9d9661df7de9e) @howking