【React】爆速でVexTabをReact-TypeScriptを用いて実装する


初めに

こんにちは、クソ雑魚のなんちゃてエンジニアです。

我は最近ReactとTypeScriptを用いてフロントエンドの実装を行って遊んでおるのじゃ。
そこで、ギターとかでよく使われる「Tab譜」というものをWeb上で実装したくなったので、Reactで実装してみた。

その際の備忘録として記載する。

VexTabとは?

上記ブログを見てもらったほうが早いだろう。
CDNで簡単にTab譜を自身のWebページで実装できるのである。

<script src="https://unpkg.com/vextab/releases/div.prod.js" />

このスクリプトタグを記述し、

<div class="vextab-auto" editor="true">
tabstave notation=true
</div>

このdivタグを実装すればおしまいなのであるから、だいぶ簡単である。
出力は以下のようになる。(一例)

Reactで使用した技術について

特段変わったことはしていない。
名前空間を少々変更したり、useEffectで副処理の実行(ここら辺は後のコード見てもらえればわかりやすいかなと)をしたりします。

UIは以下の@chakra-ui/reactを叩き込んでいるのであしからず。

では次項で具体的なコードを見てもらおう!

コード

import { Flex, Stack, Text, Textarea } from "@chakra-ui/react";
import { ChangeEvent, memo, useEffect, VFC} from "react";

type Props ={
  isEditor: boolean;
  data?: string;
  onChange: (e: ChangeEvent<HTMLTextAreaElement>)=>void;
} 

declare module 'react' {
  interface HTMLAttributes<T> extends DOMAttributes<T> {
      editor?: string
  }
}

export const VexTabComponent: VFC<Props> = memo((prop)=> {
  const {data, isEditor, onChange} = prop

  useEffect(() => {
    const head = document.getElementsByTagName('head')[0] as HTMLElement;
    const scriptUrl = document.createElement('script');
    scriptUrl.type = 'text/javascript';
    scriptUrl.src = 'https://unpkg.com/vextab/releases/div.prod.js';
    head.appendChild(scriptUrl);
}, [data]);

  return(
    <Flex>
    <Stack>
    <div className="vextab-auto" editor="false" style={{whiteSpace: 'pre-line'}}>
    {data}
    </div>
    {isEditor && (
      <>
      <Text>編集スペース</Text>
      <Textarea value={data} onChange={onChange} h="xl" />
      </>
    )} 
    </Stack>
    </Flex>
  );

});

各項目についていかにざっと説明を記載する。

import { Flex, Stack, Text, Textarea } from "@chakra-ui/react";
import { ChangeEvent, memo, useEffect, VFC} from "react";

UIの「chakra-ui」しか特段Importしていないのがわかると思う。
ほぼ特殊なことはしていない。

type Props ={
  isEditor: boolean;
  data?: string;
  onChange: (e: ChangeEvent<HTMLTextAreaElement>)=>void;
} 

親コンポーネントからのStateの型定義をTypeScriptさんで行っている。
isEditorはTabの編集スペース(TextArea)の表示該否を判定する。
dataはTabの内容
onChange関数は言うまでもないだろう。

declare module 'react' {
  interface HTMLAttributes<T> extends DOMAttributes<T> {
      editor?: string
  }
}

divタグで使用するeditorを定義してるだけ。

export const VexTabComponent: VFC<Props> = memo((prop)=> {
  const {data, isEditor, onChange} = prop
...

VexTabを使用するコンポーネントの定義。このコンポーネントを呼び出せば、どこからでもTabをページに反映できそうですね!ニッコリ
memoでレンダリング過多は防いでます。

  useEffect(() => {
    const head = document.getElementsByTagName('head')[0] as HTMLElement;
    const scriptUrl = document.createElement('script');
    scriptUrl.type = 'text/javascript';
    scriptUrl.src = 'https://unpkg.com/vextab/releases/div.prod.js';
    head.appendChild(scriptUrl);
}, [data]);

useEffectでスクリプトタグを使用せずに、ユーザがTab内容を編集実施するたびにレンダリングとCDNでの通信を発生させるように実装。
dataは何かDB等に保存されている設定なので、第二引数で指定。

return(
    <Flex>
    <Stack>
    <div className="vextab-auto" editor="false" style={{whiteSpace: 'pre-line'}}>
    {data}
    </div>
    {isEditor && (
      <>
      <Text>編集スペース</Text>
      <Textarea value={data} onChange={onChange} h="xl" />
      </>
    )} 
    </Stack>
    </Flex>
  );

});

editor=falseについて、デフォルトでVexTabについてくるエディター機能よりはDBに保存しているdataを利用することを想定し、TextAreaを使ってエディタ機能を実装した。
whiteSpace: 'pre-line'はVexTabさんが譜面を認識しやすいように改行を読み込ませるようにしました。
※それ以外は大体が「chakra-ui」なので、別途公式サイトをご覧ください。

まとめ

ざっくりとTabをReact-TypeScriptで爆速実装する方法を記載した。
まぁこんな感じでフロントで遊んだので、備忘録で記載する。

※本業はフロントではござらん。。