新しいTNG-Hooksライブラリを使用すると,通常のスタンドアロン関数に対して,リモートデータベースへのクエリやスコープ外のコンテキストにあるデータへのアクセスといった,便利でステートフル,かつ効果的なロジックを加えることが可能になる。Hooksによって実現するコードの再利用と構成は,より小さく,メンテナンス性のよい,堅牢なコードベースの実現に貢献する。
昨年のReact ConfでReactは,React Hooksによって開発者コミュニティを驚かせた。React Hooksを使用することで,ステートフルあるいはエフェクトフルな計算を単純な関数に抽象化し,React関数コンポーネント内で構成して再利用することが可能になる。機能的に純粋な計算処理にエフェクトやステートを追加する前者のアプローチは,関数を廃止してESクラスを導入するというものだ。経験の浅い開発者にとってクラスを構成することは,関数を記述するより難しいかも知れない。クラスにはまた,ロジックの実効部分が分散したり,重複したりする可能性もある。TNG-HooksはこのReact Hooksのメリットを,Reactへの依存を回避しつつ導入するためのものだ。
Reactの機能コンポーネントを模倣するため,TNGでは,2つの条件を満たすArticulated Functionという概念を導入している。その条件とは,呼び出される前にTNGデコレータによってラップされることと,実行中のある時点においてフック関数を呼び出すことだ。
次の例では,関数TNGがデコレータ,useStateがフック関数で,関数hitがArticulated Functionである。
function hit() {
var [count,updateCount] = useState(0);
count++;
updateCount(count);
console.log(`Hit count: ${count}`);
}
hit = TNG(hit);
hit(); // Hit count: 1
hit(); // Hit count: 2
hit(); // Hit count: 3
この例では,関数hitが複数回呼び出されて,それぞれ異なる値を返している。これはhitがステートフルな関数であるということだ。useStateフックがローカルなステート管理(取得,格納,状態更新)を抽象化している。フックはステート変数(count)を0に初期化して,その変数と,それを更新する関数(updateCount)を返す。
TNG-Hooksは他にも,useReducer, useEffect, useMemo, useCallback, useRefというフックを提供している。これらはそれぞれ,異なるステートフルないしエフェクトフルな処理を抽象化する。
React Custom Hooksを模倣するTNG Custom Hooksも提供される。Custom Hooksを使うことで,既存のフックを再利用して独自のフックを定義することが可能になる。TNG Custom Hooksは標準的なJavaScript関数(Articulated Functionではない)で,実行中のある時点においてArticulated Functionをコールする。TNG Custom Hooksは,それ自体がArticulated Function内から呼び出されなければならない。
// a Custom Hook, ***not*** an Articulated Function
function useHitCounter() {
// inherited TNG hooks-context
var [count,updateCount] = useState(0);
count++;
updateCount(count);
return count;
}
// will be TNG(..) Articulated twice, once as
// each button's click handler
function onClick(evt) {
// using a Custom Hook
var hitCount = useHitCounter();
console.log(`Button #${evt.target.id}: ${hitCount}`);
}
var fooBtn = document.getElementById("foo-btn");
var barBtn = document.getElementById("bar-btn");
// each click handler is an Articulated `onClick()`
fooBtn.addEventListener("click",TNG(onClick),false);
barBtn.addEventListener("click",TNG(onClick),false);
この例はCustom Hook (useHitCounter)について示したものだ。この関数は要件どおりArticulated Functionではなく,既存のuseStateフックを再利用する。useHitCounter自体は,Articulated FunctionのonClickから使用されている。fooBtnとbarBtnは,onClickイベントハンドラ内に埋め込まれたステートフルな同じuseHitCounterカスタムロジックを,それぞれが別々に再利用している。
Reactにインスパイアされたものはあるが,TNH Hooksは独立したプロジェクトである。作者のKyle Simpson氏は次のように説明する。
(TNG Hooksは)独自のモチベーションを動作を持つ,独立したプロジェクトです。理にかなう部分はReact Hooksを踏襲していますが,必要に応じて違う部分もあります。
React Hooksと同じように,Articulated Functionは呼び出しルールに従わなくてはなりません。今のところ,これらのルールを強制したり,あるいはルールに違反したことを警告するメカニズムは存在しないため,デバッグの難しい誤動作につながる可能性があります。さらに,React Hooksは実験的な新テクノロジであるため,何をするのか,何をしないのか,ということがまだ固まっていないのです。TNG HooksはReact Hooksの教訓を活かすことが可能ですが,ベストプラクティスやピットフォールを明確にするためのテストは必要かも知れません。
インストールにはtng-hooks npmパッケージが利用可能である。このパッケージは,テストコードカバレッジ100パーセントをうたっている。
TNG HooksはMITライセンス下で使用可能なオープンソースソフトウェアである。コントリビューションとフィードバックはTNG-Hooks GitHubプロジェクト経由で募集している。