はじめに
今回はReactを学び始めて間もない初心者が、カスタムフックについて学んだので、備忘録がてらまとめてみたいと思います。
Ract Hook(フック)とは
React Hook
とは、フックによって関数コンポーネント中で状態や、ライフサイクルを扱うための機能です。
フックは扱う対象や、機能によって複数の種類があり、Reactが公式に提供しているフックはこちらから確認できます。
また、公式ドキュメントにフックについて下記のようにあります。
要するにフックとは?
フックとは、関数コンポーネントに state やライフサイクルといった React の機能を “接続する (hook into)” ための関数です。フックは React をクラスなしに使うための機能ですので、クラス内では機能しません。
https://ja.reactjs.org/docs/hooks-overview.html#but-what-is-a-hook
Reactには、クラスコンポーネントと関数コンポーネントがありますが、フックの登場で関数コンポーネントでもクラスコンポーネントと同様の機能が使えるようになったということで、現在では関数コンポーネントでの開発が主流になっているとのことです。
カスタムフックの実装
フックのルール
公式サイトにフックのルールについて以下のようにあります。
- フックは関数のトップレベルのみで呼び出してください。ループや条件分岐やネストした関数の中でフックを呼び出さないでください。
- フックは React の関数コンポーネントの内部のみで呼び出してください。通常の JavaScript 関数内では呼び出さないでください(ただしフックを呼び出していい場所がもう 1 カ所だけあります — 自分のカスタムフックの中です。これについてはすぐ後で学びます)。
https://ja.reactjs.org/docs/hooks-overview.html#rules-of-hooks
上記のルールに違反してフックを呼び出すと、ビルドエラーまたは実行時エラーが発生します。
これは描画ごとに呼び出されるフックの数と順番を同じにするためです。
カスタムフック
フックを使用する関数を新たに定義して、それを関数コンポーネントのトップレベルで呼び出すことができます。
このような関数を実装することで複数のフックを組み合わせたカスタムフックが実装できます。
公式ドキュメントでは下記のように説明されています。
カスタムフックはstateを使うロジック(データの購読を登録したり現在の値を覚えておいたり)を共有するためのもの
https://ja.reactjs.org/docs/hooks-custom.html
カスタムフックの実装
実際に簡単なカスタムフックを作成したいと思います。
以下はテキストボックスに文字を入力して際に、入力された文字が表示されるといったものになります。
関数コンポーネント外で
useInput
というカスタムフックを定義しています。カスタムフックの名前は他のフックと同様に
use
から始まる名前にします。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import React, { useState, useCallback } from "react" // input向けにコールバックと現在の入力内容をまとめたフック export const useInput = () => { const [state, setState] = useState('') const onChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => { setState(e.target.value) }, []) // 現在の入力内容とコールバック関数だけ返す return [state, onChange] as const } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import { useInput } from "../hook/UseInput" const Input = () => { const [text, onChangeText] = useInput() return ( <div> <input type="text" value={text} onChange={onChangeText} /> <p>Input: {text}</p> </div> ) } export default Input |
Input
を実行してテキストボックスに入力すると、以下のような挙動になります。
さいごに
これを覚えないとReactが始まらないくらい大事な機能だと思うので、頭に叩き込んでいきたいと思います。