疲れたあなたを癒す「ライフゲーム」コンポーネントライブラリを作った
👾はじめに
この Gif をご覧ください。
これはライフゲームと呼ばれる簡単なゲームを描画したものです。
生き物が動いているのをみているようで、ぼんやり眺めてるだけでも心が落ち着く感じがありますね(?)
業務には全く活きないライフゲームですが、webページの遊び要素として取り入れてもらえたらなと思います。codesandboxにて触ってみてください。
🧑💻技術的な話
以下の2点について書きます。既にご存じの方はご容赦ください🙏 (ライフゲームの作成自体は簡単なので割愛します)
- key を使ったコンポーネントの再生成
- Vite + React + TypeScript でのコンポーネントライブラリ作成
key
を使ったコンポーネントの再生成
🔑 結論から書くと、「何かに応じてコンポーネントをステートごと再生成[1]したいときはkey
プロパティを使うと良い」 です。
以下に例を示します。
function App() {
const key = useKeyOnResize(); // ウィンドウの面積を返すカスタムフック
return (
<Component key={key} />
);
}
具体的に説明します。
本ライブラリでは、ライフゲームの描画を
- (デフォルトだと)ライフゲームフィールドが画面いっぱいに広がるように、縦横の細胞数を計算する
- 各細胞の状態ステートを 1.で計算した形状の配列で管理する
- その配列の通りに DOM を配置する
という手順で行っています。
そのため、もし画面サイズが変更された場合には、新しい画面幅に応じた形状の二次元配列を再度生成する必要があります。そこで色々と調査していた時に以下の stackoverflow の回答に遭遇し、上記の学びを得ました。
map などの処理で key を書かないと React に怒られるのでいつも思考停止で使っていましたが、 key
をコンポーネントの再生成のために使う という発想が自分にとっては新しく、非常に良い学びでした。
📝 Vite + React + TypeScript でのコンポーネントライブラリ作成
本ライブラリでは Vite, React, TypeScript を採用しました。
この構成でコンポーネントライブラリを作る記事が少なかったので、参考になった記事を紹介するとともに、補足をしておきます。
この記事がとてもわかりやすく参考になりました🙏
この記事は非常にわかりやすかったのですが、 TS 対応がオプショナルなものとして書かれており、私がパッケージ作成の初心者すぎて最終形のイメージがつきづらく、少し苦労しました。同じ技術構成でライブラリを作る初心者の方に向けてメモを残しておきます。
今回の技術構成(react + ts)なら、 vite.config.ts
と package.json
は次のようになるはずです。
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.ts'),
name: 'ReactLifeGame',
fileName: (format) => `${好きな名前(ライブラリ名など)}.${format}.js`, // *1
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
},
},
},
},
});
{
"name": "...",
"version": "...",
"files": [
"dist", // ビルドされたもの
"types" // 自動生成された型定義ファイル
],
"types": "types/index.d.ts",
"main": "./dist/${ vite.config.ts の *1 で指定したファイル名}.umd.js",
"module": "./dist/${ *1 で指定したファイル名}.es.js",
"exports": {
".": {
"import": "./dist/${ *1 で指定したファイル名}.es.js",
"require": "./dist/${ *1 で指定したファイル名}.umd.js"
}
},
"scripts": {
...
"prepare": "yarn build" // パッケージの publish に呼ばれる
},
"dependencies": {
...
},
"devDependencies": {
...
},
"peerDependencies": {
"react": "...",
"react-dom": "..."
},
}
最後に
作成したライフゲームのコンポーネントの紹介と、開発時の学びをまとめました。
少しでもライフゲームを楽しめたという方や、 key
の使い方なるほどな〜となった方など、「いいね」をよろしくお願いします!
-
本記事では再生成(ステートの初期化を伴う)と再レンダリング(ステートは維持される)を区別しています。 ↩︎
Discussion