カスタムフック
カスタムフックとは
カスタムフックとは任意の処理をまとめた自作のフックのことで、ロジックをコンポーネントから分離したり、複数のコンポーネントからロジックを再利用したりすることが可能となる。
- useStateやuseEffectのようにuseXxxと命名する。
- src/hooksディレクトリに格納するのが一般的。
- カスタムフックとして定義した関数は、Stateや関数をオブジェクトでまとめてreturnする。
(戻り値は自由に決められるが、オブジェクトで返すのが一般的)
カスタムフックの必要性
例えば、以下のコンポーネントはhandleFetchUsersButtonClick関数でフラグの設定・データの取得・データの変換を行っているためコード量が増えてしまっている。
コンポーネントは与えられたpropsに基づいて画面の見た目を構築することを責務とし、複雑なロジック部分は分離すべきである。
また、他のコンポーネントでもユーザー取得APIを使う場合、ロジック部分が分離してあれば再利用することができる。
import React, { FC, useState } from 'react';
type User = {
id: number,
name: string,
age: number
}
const Sample2: FC = () => {
const [users, setUsers] = useState<User[]>([])
const [isLoading, setIsLoading] = useState<boolean>(false)
const [isError, setIsError] = useState<boolean>(false)
const handleFetchUsersButtonClick = () => {
setIsLoading(true)
setIsError(false)
fetch("/users.json")
.then((res: Response) => res.json())
.then((json: User[]) => {
json.map((user: User)=> user.name = `${user.name}さん`)
setUsers(json)
})
.catch(() => setIsError(true))
.finally(() => setIsLoading(false))
}
return (
<div>
<h1>sample2</h1>
<button onClick={handleFetchUsersButtonClick}>users.json取得</button>
<p>{ isLoading && '読み込み中'}</p>
<p>{ isError && 'エラー'}</p>
{ users.map((user: User)=> <p key={user.id}>{user.name}</p>)}
</div>
);
}
export default Sample2;
カスタムフックの実装
mkdir src/hooks;
touch src/hooks/useFetchUsers.tsx
import React, { useState } from 'react';
import type { User } from '../types/user';
export const useFetchUsers = () => {
const [users, setUsers] = useState<User[]>([])
const [isLoading, setIsLoading] = useState<boolean>(false)
const [isError, setIsError] = useState<boolean>(false)
const handleFetchUsersButtonClick = (): void => {
setIsLoading(true)
setIsError(false)
fetch("/users.json")
.then((res: Response) => res.json())
.then((json: User[]) => {
json.map((user: User)=> user.name = `${user.name}さん`)
setUsers(json)
})
.catch(() => setIsError(true))
.finally(() => setIsLoading(false))
}
return {users, isLoading, isError, handleFetchUsersButtonClick}
}
利用時
import React, { FC, useState } from 'react';
import type { User } from './types/user';
import { useFetchUsers } from './hooks/useFetchUsers';
const Sample2: FC = () => {
const {users, isLoading, isError, handleFetchUsersButtonClick } = useFetchUsers()
return (
<div>
<h1>sample2</h1>
<button onClick={handleFetchUsersButtonClick}>users.json取得</button>
<p>{ isLoading && '読み込み中'}</p>
<p>{ isError && 'エラー'}</p>
{ users.map((user: User)=> <p key={user.id}>{user.name}</p>)}
</div>
);
}
export default Sample2
コメント