React + typescript カスタムフックの使い方
はじめに
今回は、カスタムフックについて紹介しようと思います。
(なかなか、typescript の情報がなくて困りますね。。。)
今回は、以下を参考にさせて頂きました。
では、早速本題へ移りましょう。
カスタムフックとは
カスタムフックとは、他のhooks
をまとめるためのものです。useState
やuseEffect
といった様々なhooks
を一つのファイル内で使用して、コードが長くなってしまったことはないでしょうか?コードが長いと読む気も失せますし、チーム開発だとコードレビューが厳しいです。(現在チーム開発をしているので、できるだけ気にしています。)hooks
をまとめてしまってコードをスッキリさせたい!そんな時に、活躍するのがカスタムフックです。
実際に、ハンズオン形式でやってみましょう。
カスタムフックの使い方
今回は、ボタンを押すと背景色が変化するコードを準備しました。
まずは、プロジェクトを準備しましょう。
npx create-next-app --ts
プロジェクトができたら、以下のソースコードをsrc/pages/index.tsx
にコピペしましょう!
import type { NextPage } from "next";
import { useState } from "react";
const Home: NextPage = () => {
const [color, setColor] = useState<"red" | "blue">("red");
const [bgColor, setBgColor] = useState<"yellow" | "black">("yellow");
return (
<div
style={{
color: color,
background: bgColor,
}}
>
<h1>Hello</h1>
<div>
<h2>テキストボタン</h2>
<button
onClick={() => {
setColor("red");
}}
>
赤
</button>
<button
onClick={() => {
setColor("blue");
}}
>
青
</button>
</div>
<div>
<h2>背景ボタン</h2>
<button
onClick={() => {
setBgColor("yellow");
}}
>
黄
</button>
<button
onClick={() => {
setBgColor("black");
}}
>
黒
</button>
</div>
</div>
);
};
export default Home;
これで、以下のような画面が表示されると思います。各ボタンを押すと、テキストや背景の色が変化することを確認してください。
(配色のセンスがないのは、申し訳ありません。。。)
では、本題に入ります。今回は、現在index.tsx
内で使用している 2 つのuseState
を外に出して、このファイルを読み取り専用にします。では、src
配下に新しいフォルダを作成しましょう。私は、hooks
というフォルダを作成します。作成後、hooks
の配下にtextSetColor.ts
とbgSetColor.ts
を作成します。これで、現在のフォルダ構成は以下のようになっているかと思います。(フォルダの構成は参考程度で大丈夫です。)
src
├─pages
| index.tsx
└─hooks
textSetColor.ts
bgSetColor.ts
まずテキストの色の状態管理している、以下のコード
const [color, setColor] = useState<"red" | "blue">("red");
このコードをカスタムフックにしてみましょう。
textSetColor.ts
に移って以下の関数名で関数を定義しましょう。(関数名が重要になります。)
export default function useTextColor() {}
その後、先ほど紹介したindex.tsx
に定義しているテキストの色の状態を管理しているuseState
を、先ほど定義した関数の中に移してください。次に、useState
がないため、エラーが出ているためuseState
をimport
しましょう。これで、以下のようになっているかと思います。
import { useState } from "react";
export default function useTextColor() {
const [color, setColor] = useState<"red" | "blue">("red");
}
ここまで来たら、後は簡単です。このファイルを作成する前、index.tsx
ではuseState
のcolor
とsetColor
の二つの変数と更新用関数を使用していました。しかし現在、これら 2 つがなくてindex.tsx
内ではエラーがでています。エラーを解消する為には、color
とsetColor
を渡せばエラーが治りますね。ということで、戻り値にcolor
とsetColor
を返してあげましょう。以下のようにします。
import { useState } from "react";
export default function useTextColor() {
const [color, setColor] = useState<"red" | "blue">("red");
return {color , setColor}
}
ここで、戻り値は{}
これで返してあげましょう。配列で返すことも可能ですが、配列で返してしまうと、この後、使用する際に型の宣言を無駄にしてあげる必要が出てしまい面倒になります。「{}
」で、返しておくと型の推測をしてくれるため、楽できます。基本は、この返し方をすれば問題ありません。
最後に、index.tsx
に移り、先ほど作成したカスタムフックを呼び出してあげましょう。呼出し方は、以下のようになります。
const { color, setColor } = useTextColor();
index.tsx
に記述すると、以下のようになります。
import type { NextPage } from "next";
import { useState } from "react";
import useTextColor from "../hooks/textSetColor";
const Home: NextPage = () => {
const { color, setColor } = useTextColor();
const [bgColor, setBgColor] = useState<"yellow" | "black">("yellow");
return (
<div
style={{
color: color,
background: bgColor,
}}
>
<h1>Hello</h1>
<div>
<h2>テキストボタン</h2>
<button
onClick={() => {
setColor("red");
}}
>
赤
</button>
<button
onClick={() => {
setColor("blue");
}}
>
青
</button>
</div>
<div>
<h2>背景ボタン</h2>
<button
onClick={() => {
setBgColor("yellow");
}}
>
黄
</button>
<button
onClick={() => {
setBgColor("black");
}}
>
黒
</button>
</div>
</div>
);
};
export default Home;
これで、先ほどまで出ていたエラーが解消されていると思います。実際に、動きを確認してみましょう。問題なく動いてますね。
ここで、カスタムフックのポイントです。カスタムフックの関数名が重要だと途中記載しましたが、カスタムフックの関数名は必ずuse~
と先頭にuse
をつける必要があります。今回は、カスタムフックの名前をuseTextColor
としましたね。もし、このようにしないとカスタムフックと認識されずエラーが出てしまいます。また、useState
と違い左辺が以下のようになっていることにも注意です。(今回、戻り値を{}
で返しているため。)
const { color, setColor } = useSetColor();
配列で返した際は[]
で囲みますが、カスタムフックなのか分かりづらく、型の定義を再度する必要があり非常に使い勝手が悪いです。カスタムを使用する際は{}
で変数や関数を返しましょう。同様に、背景色の色を管理しているuseState
もカスタムフックにします。ここで、できる方は、ご自身でやってみましょう。
ちなみに、コードは以下のようになります。
import { useState } from "react";
export default function useBgColor() {
const [bgColor, setBgColor] = useState<"yellow" | "black">("yellow");
return { bgColor, setBgColor };
}
import type { NextPage } from "next";
import useBgColor from "../hooks/bgSetColor";
import useTextColor from "../hooks/textSetColor";
const Home: NextPage = () => {
const { color, setColor } = useTextColor();
const { bgColor, setBgColor } = useBgColor();
return (
<div
style={{
color: color,
background: bgColor,
}}
>
<h1>Hello</h1>
<div>
<h2>テキストボタン</h2>
<button
onClick={() => {
setColor("red");
}}
>
赤
</button>
<button
onClick={() => {
setColor("blue");
}}
>
青
</button>
</div>
<div>
<h2>背景ボタン</h2>
<button
onClick={() => {
setBgColor("yellow");
}}
>
黄
</button>
<button
onClick={() => {
setBgColor("black");
}}
>
黒
</button>
</div>
</div>
);
};
export default Home;
以上で終了です。実際に動かしてみましょう。問題なく動作しますね。今回は、二つに分割しましたが、一つにまとめることも問題なく可能です。
そちらは、是非チャレンジしてみましょう!きっと力になるはずです!
最後に
今回は、カスタムフックを紹介させて頂きました。まだまだ学ぶことが多く大変ですが、なんとか頑張っています。まだまだ、学ぶことが多くあるためこれからも記事は自分の知識として残し、共有できるように頑張ろうと思います。何か質問や指摘等があれば遠慮なく、よろしくお願いします。では、また次回の記事で!
Discussion