昔を知らない初級者が、Riot.js v9をいじってみる

## はじめに（読み飛ばしOK）
こんにちは。
プログラム及び、JavaScript初級者です。
ネットを色々と漁っていたら、ライブラリというものの存在を知りました。
ライブラリには沢山の種類があようです。どれか面白そうなものは無いか？見ていたら、カスタムタグというのを使用する、**Riot.js** を見つけました。

Riot.js の記事をQiitaで検索しても最近の記事はあまり見つけられず、人気や使用頻度なども下火なのかな？とも思いました。
使い方の記事も少な目で大変そうなのですが、[公式ページ](https://riot.js.org/ja/)は日本語表示もあり、とっつきやすさはあると思いました。練習がてら少しいじってみようと思います。

尚、「Hello world」の表示に関しては、チュートリアルって事で先に済ませてあります。

## 作ったもの　log_list

作ったものは、テキストエリアに打ち込んだ文字がlogとしてlist状に下へ打ち出されていくものになります。色々盛り込んでみようとも思い、見た目掲示板風にしてみました。意識的に組み込んでみたものは、以下の様になります。

- 別のjsファイルをimportし、propsにマウント
- Riot.jsのバージョン取得と表示

![log_list_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761147/ddf5e021-84fb-8d9d-6d51-42231e7d849d.png)

### 作成したファイル
- index.html　コンポーネントのマウントを司る
- log_list.riot　カスタムタグのファイル、拡張子は.riot
- id.js　props用
- style.css　スタイルシート

### index.html (\<body\>)
```html
<body>
  <!-- カスタムタグの表示位置-->
  <log_list />

  <!-- <log_list/> は外部ファイルで指定 -->
  <script src="./log_list.riot" type="riot"></script>
  
  <!-- cdnで riot.js とコンパイラ -->
  <script src="https://unpkg.com/riot@9/riot+compiler.min.js"></script>
  
  <!-- コンパイルとマウント、他import -->
  <script type="module">
          import {id} from "./id.js" // 別jsファイルをimport

    (async function main() {
      await riot.compile();

      riot.mount('log_list', {
          title: 'log_list ',
          ver: ` @ riot.js ${riot.version}`, // バージョン取得
          id: id, //importした別jsファイルをpropsとしてマウント
      })
    }())
  
  </script>

</body>
```
Riot.jsの昔の記事を見ると、V3かV4の辺りで大きな書式変更があったらしいです。その後、細かい変更などを経て、今(2024 4月現在)ではv9となりました。尚、`{riot.version}` で常にその時に読み込まれているバージョンを取得し、表示させています。便利です。

### log_list.riot（カスタムタグ名 log_list）
```html
<log_list>
    <div id="display">
        <h1>{ props.title }<span>{ props.ver }</span></h1>
        <textarea id="textarea" placeholder="{props.id.textarea.placeholder}"></textarea>
        <br> 
        <button id="add" onclick="{addText}">{ props.id.add.value }</button>
        <br>
        <br> 
        <div id="below">{ props.id.below.value }</div>
        <hr>

        <!--this.update({}) で更新される個所 -->
        <!--each による配列のループ処理 -->
        <div each="{item in state.logs}">
            <!--三項演算子でclass設定　new表示用 -->
            <span class="{item.index == state.logs.length ? 'newest': ''}">{ item.date }</span>          
            <div class="container">
                <div>
                    { item.index }.&nbsp;
                </div>
                <div class="indent">
                    { item.text }
                </div>
            </div>
            <hr>
        </div>
    </div>

    <script>
        export default {
            /*---マウント前に1回実行、state設定 ---*/
            onBeforeMount(props, state) {
                this.state = {
                    logs: [],
                    index: 0,
                }
            },
            
            /*---onclickで呼ばれる関数 ---*/
            addText() {
                if (this.$("#textarea").value != '') {
                    this.state.logs.unshift({
                        index: this.state.logs.length + 1,
                        date:  this.date(new Date()), // this を付けて別関数呼び出し
                        text: this.$("#textarea").value, // this.$("セレクター")で、要素へアクセス
                    });
                
                    this.$("#textarea").value = '';

                    this.update ({ //state内容が画面に適用される
                        logs : this.state.logs,
                    })
                }
            },
            
            /*---日付表示作成用関数 ---*/
            date (d) {
                const week = ["日", "月", "火", "水", "木", "金", "土"];
                return (
                    String(d).replace(
                        /^.*(\d{4})\s(\d{2}:\d{2}:\d{2}).*$/, 
                        `$1/${d.getMonth() + 1}/${d.getDate()} (${week[d.getDay()]}) $2`
                    )
                )
            },
        }
    </script>
</log_list>
```
日付表示やら何やらで、長くなってしまいました。
主な留意点としては、**`this.update({})`をやってあげないと、stateの変更内容が画面表示に適用されない** ところでしょうか？

### id.js（お試し）
```js
export const id = {
    textarea: {
        placeholder: 'Please text here...'
    },

    add: {
        value: 'Add',
    },

    below: {
        value: '▼ Below here is the log'
    },

}
```
この程度のコードでこういった外部ファイルは本当は必要でもないんですが、お試しで作ってみました。

ただ、こういった **外部ファイルの importやexport の方法がよく分からず**、しょうがないので、index.htmlでimportし、props経由でデータの取得がたまたまうまくいったので、こういう方法を取ってみました。
正直、**これであっているのか？**

## style.css
```css
span {
    font-size: small;
}

#display {
    width: 400px;
}

#textarea {
    width: 100%;
    height: 100px;
    resize: none;
}

::placeholder {
    color: darkgray;
}

.newest::after {
    content: ' new !';
    color: red;
}

.container {
    display: flex;
}

.indent {
    white-space: pre-wrap;
}
```

特にどうってことのないCSSです。
log_list.riotファイルの中に\<style\>\</style\>を設けて記述しても良かったんですが…
もしかしたらCSSや上記のJSファイルなど、**拡張子.riot のファイル1つにまとめるのが本来の目的なのかもしれません？**

## まとめ　Riot.js を使って見た感想

- 思ったよりも使いやすい
- 学習量は、多くないと思う
- **`this` が多すぎ(笑)**
- `this.$("セレクター")`は、jQueryやUmbrellaで代用しても良さそう
- `onBeforeUpdate(props, state) {`
`　 //更新前にコンテキストデータの再計算が許可されている`
`}`
`onUpdated(props, state) {`
`　 // update が呼び出され、コンポーネントのテンプレートが更新された直後`
`}`<br> この辺りの[ライフサイクル](https://riot.js.org/ja/documentation/#%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF)に柔軟性を感じさせる
- **別jsファイルなどのimport方法がこれであってるのか分からない**というか、**拡張子.riot のファイル1つにまとめるのが本来の目的なのかもしれません？** よく分かりません…

以上、Javascriptのライブラリ、Riot.jsを使って見た感想でした。

### 今後いじってみたいもの
- Node.js とか？
- Svelte　とか？

## 参考サイト様

https://qiita.com/nnahito/items/fd631d9a312107bf28d8