FizzBuzz ボタンを作りながら React Hooks を学んでいきます。
目次はこちら。
Custom Hook を作る
前回まででひととおり React Hooks を使った FizzBuzz ボタンは完成しました。
今回は Custom Hook を作ります。
Hook を組み合わせて独自の Hook を作ることができます。これを Custom Hook と呼びます。
今回は簡単な Custom Hook を作ります。
前回、マウントとアンマウント時の処理を Effect Hook を使って作りました。
const FizzBuzz: React.FC<Props> = React.memo((props: Props) => {
...
useEffect(() => {
console.log('mount');
return () => console.log('unmount');
}, []);
...
useEffect
の第1引数にマウント時の処理を指定し、その戻り値にアンマウント時の処理を指定します。
これは少しわかりにくいので、第1引数にマウント時の処理、第2引数にアンマウント時の処理を指定するような関数(useMount
)を作ります。
const useMount = (
mount: () => void,
unmount?: () => void
): void | (() => void) => {
useEffect(() => {
mount();
return unmount;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
};
const FizzBuzz: React.FC<Props> = React.memo((props: Props) => {
...
useMount(() => console.log('mount'), () => console.log('unmount'));
...
ここで注意しなければいけないのは useEffect
の第2引数です。
修正前の実装の通り、第2引数には []
を渡せば良いのですが、VS Code でファイルを保存すると、eslint-plugin-react-hooks が補完をして [mount, unmount]
となってしまいます。
これでは期待通りの動作になりませんので、補完されないようにコメントを記述しています。
useMount
は JSX を使用していませんので、別ファイルに切り出す際には拡張子を ts
としておきます。
import { useEffect } from 'react';
export const useMount = (
mount: () => void,
unmount?: () => void
): void | (() => void) => {
useEffect(() => {
mount();
return unmount;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
};
↓こんな感じで使います。
import React, { useState, useCallback } from 'react';
import FizzBuzzView from './FizzBuzzView';
import { fizzBuzz } from './common';
import { useMount } from './hooks';
type Props = {
// props で count の初期値を受け取る
initialCount: number;
};
const FizzBuzz: React.FC<Props> = React.memo((props: Props) => {
console.log('render');
const [count, setCount] = useState(props.initialCount);
// eslint-disable-next-line no-shadow
const plus1 = useCallback(() => setCount(count => count + 1), []);
const clear = useCallback(() => setCount(props.initialCount), [
props.initialCount,
]);
useMount(() => console.log('mount'), () => console.log('unmount'));
const message = fizzBuzz(count);
return (
<FizzBuzzView count={count} message={message} plus1={plus1} clear={clear} />
);
});
export default FizzBuzz;
今回作成したソースコードはこちら。
次回はもうひとつ Custom Hook を作ります。