LoginSignup
12
0

React Hook Roulette - React で作る、ミニマルなルーレット

Last updated at Posted at 2023-12-10

React でミニマルなルーレットを作成するためのライブラリを作成しました。

ライブデモはこちらで確認できます。

作成のモチベーション

既存の React ベースの類似ライブラリでは、以下を満たせるものが見当たらずでしたので、作成に至りました。

  • 細かなライフサイクル(スピンアップ・スピンダウン・スピンストップ)にアクセス可能
  • 外部からの開始・停止の制御が可能

表示制御には Canvas API を使用しています。

セットアップ

npm

npm install react-hook-roulette

pnpm

pnpm add react-hook-roulette

yarn

yarn add react-hook-roulette

コードサンプル

import { Roulette, useRoulette } from 'react-hook-roulette';

const App = () => {
	const items = [
		{ name: "label1" },
		{ name: "label2" },
		{ name: "label3" },
		{ name: "label4" },
		{ name: "label5" },
		{ name: "label6" },
	];
	const { roulette, onStart, onStop, result } = useRoulette({ items });

	return (
		<div>
			<Roulette roulette={roulette} />
			<button type="button" onClick={onStart}>Start</button>
			<button type="button" onClick={onStop}>Stop</button>
			{result && <p>Result: {result}</p>}
		</div>
	);
};

API リファレンス(一部抜粋)

RouletteItem

ルーレットの要素として作成する、データ型です。

const items = [
    { 
        name: "label1"
        bg: "#cccccc",
        color: "#000000",
        weight: 1.5,
    },
    {
        name: "label2"
    },
        ...
Property Type Description
name string ルーレット要素に表示する、名称を記載します。
bg string? 背景色を hex 形式で指定します。(オプション)
color string? 表示する名称の、文字色を指定します。 (オプション)
weight number? 他の要素との相対的な大きさを指定します。(オプション)

useRoulette Hook

const { roulette, onStart, onStop, result } = useRoulette({ items });

Props

Property Type Description
items RouletteItem[] 前述のルーレット要素です。
onSpinUp () => void 回転が開始した際に実行されるコールバック。
onSpinDown () => void 回転速度が低下した際に実行されるコールバック。
onSpinEnd (result: string) => void 回転が終了した際に実行されるコールバック。
options Partial<RouletteOptions> ルーレットの詳細をカスタマイズするオプションです。速度の制御や、result として判定する角度の指定が可能です。

Return Values

Property Type Description
roulette RouletteCanvas Roulette コンポーネントに設定します。
result string ルーレットストップ時に、結果が渡されます。
onStart () => void 実行時、回転が開始します。
onStop () => void 実行時、停止が開始します。

その他オプションを含めた、詳細については下記に記載しています。
https://github.com/camiha/React-Hook-Roulette/tree/main#api-references

今後の予定

  • Canvas context にアクセスする API の作成
  • 責務の分離を踏まえたリファクタ
    • 状態制御を別のレイヤに移動したほうがいい関数が一部存在
  • テストコードの追加

あとがき

実装について

ユーザーが定義するオプションにおいて、デフォルトとなる値をどのように定義・どのようにマージするかは、検討の余地がありそうです。今回は持っている知識でまとめてしまいましたが、いろんなライブラリを読んで知見を溜めていきたいところ。(別に取り組んでいるやつは Vite の defineConfig を参考にしています。)

TypeScript、分かってきたと思うのも束の間で。
知らないことがたくさん出てくるので沼ですね...

ライブラリ設計と開発の難しさについて

ユースケースを考えたり、組み込まれるであろう周辺コードを想像した上で、React の機能や仕組みを把握していないと適切な実装に起こせないよね、と改めて感じました。ライブラリ作成は求められる知識の幅が広いなぁと思った次第です。

加えて、今回のような事をしようとすると、React 外の DOM API に関する知識の重要度が増しますね。(requestAnimationFrame, Canvas 周辺)

他のライブラリを読むモチベーションについて

似たような実装を起こそうとした時「そう言えばあのライブラリは似たようなことしているよな...」からコードリーディングをする機会がありました。(React Hook Form が副作用をどう扱っているかが知りたくなりました) 結果的には同じ実装方針だったのですが、愛されているライブラリと実装が似通っていると、自信を持つきっかけになりますね。(副作用内での値更新になります。useRef 様様ですね)

React Hook Form、いつも何気なく使っているけど、何気なく使えるのはその優秀な API 設計に根ざしているんだなぁと感心しました。

最後に

お読みくださりありがとうございます。
ライブラリ開発はいろんな視点で物事を見るきっかけになれるのでおすすめです。
プログラミングの楽しみがまた一歩広がりました、まだまだカタチにしたいものがたくさんあります。

React プログラマと DOM API の魔術師たちに感謝を込めて。
来年も良きレンダリングライフを。

12
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
0