はじめに
D言語くんは好奇心が旺盛なことで知られており、常にTwitterで自身に関するツイートを監視しています。
それこそまさしく365日24時間、監視中の鬼気迫る形相たるやD言語くんの如しです。
また、毎年そのD言語くんアイが捉えていたと思われるツイートを長年のD言語くん研究家である @simd_nyan 氏がまとめてレポートとして公開されています。
- 2019年 : https://gist.github.com/simdnyan/a82a49ed5a2d4e559b393f20746a6587
- 2018年 : https://gist.github.com/simdnyan/1f9f19c523100ceeadc8f67b017b7ddb
- 2017年 : https://gist.github.com/simdnyan/02fbf4106ad9bd39cf02eb418ced5fa5
このレポートはツイートのIDを列挙したものである、ということまではわかっていますが、とても人間が理解できるものではありません。
そこでD言語くんの御心を理解するため、近年のWeb技術をもってビューアーを作り、そのレポートの真実に迫っていきたいと思います。
(とか言いながら同じことをやってもう3年目になります)
概要
D言語くんが見ていたものが何なのか、理解するために長ったらしい文章など必要ありません。
以下のリンクからビューアーを参照してください。
毎度半日くらいでほぼゼロから書いているため、今年も今年で見た目はこんな感じです。
なお、0以上を想定するカウンター値が初手-1を押すだけで負の値を取るバグっぷりです。
「これでよく公開できたな」と称賛してください。こんな感じで大丈夫です。知らんけど。
詳細
こちらのソースは以下のリポジトリに一式置いてあります。
日ごろ使っている安定のサンドボックス的最小構成である TypeScript + React + parcel をベースに Material UI + gh-pages を追加している感じです。
React的な話をしておくと、最近流行ってると噂の React Hooks を使って埋め込みツイートを表示するコンポーネントを作り、あとはgistからテキスト取ってきて加工、適当にスライダーなど揃えて突貫工事でビューアーとして仕立てました。
今年は年を切り替えられるようにしたので、今後はそこらへんをメンテするだけでD言語くんと共に歩むことができますね!
準備
埋め込みツイートの表示は、公式で提供されるスクリプトを読み込んでやれば簡単に行えます。
TypeScriptで使う定義と合わせて以下のようにしておきます。
<script src="https://platform.twitter.com/widgets.js"></script>
interface Twttr {
widgets: {
createTweet(id: string, container: HTMLElement, options: {}): Promise<HTMLElement>;
};
}
declare const twttr: Twttr;
(Windowインターフェースを拡張するnamespaceを書くほうが良い気がしましたが、気が向いたら書き換えることにします)
埋め込みツイート用コンポーネント
イマドキなら useRef と useEffectを使えば楽勝ですね。(本当か?)
Twitterのスクリプトが提供する関数を使えば簡単に埋め込みツイートを表示できます。
関数の引数に使うため、ノードの参照を取ってきて、useEffect
の中で呼び出します。
createTweet
が勝手にノードの挿入までやってくれるので使うのは楽なのですが、戻り値がPromiseなので、IDを切り替えるときに前のツイートを消すのがちょっと面倒です。
普通は初期化したら表示しっぱなしだと思うのでこれは仕方ないですかね。
useEffectの戻り値でノードを削除する処理を返すあたりがポイントです。
interface TweetProps {
tweet: string;
}
function Tweet({ tweet }: TweetProps) {
const containerRef = React.useRef<HTMLDivElement>();
React.useEffect(() => {
const t = twttr.widgets.createTweet(tweet, containerRef.current, {});
return () => {
t.then(e => {
if (e && e.parentNode) {
e.parentNode.removeChild(e);
}
});
};
}, [tweet]);
return <div ref={containerRef}></div>
}
振り返り
- 久々にMaterial UIのサイトに行ったら日本語で表示できるようになっていた
- https://material-ui.com/ja/
- (コンポーネント名を翻訳するのはやめてほしい)
- 噂のSuspenseを使いたかったけど、せっかくなら…とuseRefと組み合わせたらイマイチうまく動かず諦めた
- 紹介記事がどれもグローバル変数に入れているのは何か理由がありそうな気がする
- useReducer使うように書き換える予定が前日に作業開始したため間に合わず
- インクリメント/デクリメント周り、どう見てもdispatchで変化量を指定する方が良いですね。
というわけで以上です!
アドベントカレンダーの準備は計画的に、用法容量を守って正しくご参照ください!