前回、【React】カスタムフックの概要・メリット・使いどころでカスタムフックの概要について紹介しました。
今回はカスタムフックの具体的な作成手順について紹介します。
目次
今回利用するサンプルコードについて
今回は『API経由で取得したTodoリストの内容を表示する』というコンポーネントを例にカスタムフックの作成手順について紹介します。
最終的には『Todoリストの内容を表示するコンポーネント』と『API経由でTodoリストを取得するカスタムフック』に分割します。
カスタムフック導入前
以下はカスタムフック導入前のコンポーネントです。
データ取得とUI構築のコードが混在しているため可読性があまりよくありません。
App.tsx
import axios from "axios";
import { useEffect, useState } from "react";
type TodoItem = {
id: number;
content: string;
completed: boolean;
};
const App = () => {
const [todos, setTodos] = useState([] as TodoItem[]);
useEffect(() => {
const getTodoRequest = async () => {
const response = await axios.get("http://localhost:4000/todos");
const todos = response.data;
return todos;
};
getTodoRequest().then((todos) => setTodos(todos as TodoItem[]));
}, []);
return (
<>
<h2>TodoList</h2>
<ul>
{todos.map(({ id, content }) => (
<li key={id}>
<div>{content}</div>
</li>
))}
</ul>
</>
);
};
export default App;
カスタムフック導入後
以下は今回のゴールであるカスタムフック導入後のコードです。
src/lib/hooks/useTodos.ts
import axios from "axios";
import { useEffect, useState } from "react";
type TodoItem = {
id: number;
content: string;
completed: boolean;
};
const useTodos = () => {
const [todos, setTodos] = useState([] as TodoItem[]);
useEffect(() => {
const getTodoRequest = async () => {
const response = await axios.get("http://localhost:4000/todos");
const todos = response.data;
return todos;
};
getTodoRequest().then((todos) => setTodos(todos as TodoItem[]));
}, []);
return todos;
};
export default useTodos;
App.tsx
import useTodos from "./lib/hooks/useTodos";
const App = () => {
const todos = useTodos();
return (
<>
<h2>TodoList</h2>
<ul>
{todos.map(({ id, content }) => (
<li key={id}>
<div>{content}</div>
</li>
))}
</ul>
</>
);
};
export default App;
API経由のデータ取得は例えばSWRを利用する方法などもあります。
カスタムフックの実装の手順について
カスタムフックの実装の手順をまとめると以下のようになります。
- コンポーネントのコードから分離させたいフックを検討する
- 関連するフックをカスタムフックへ移動する
- コンポーネントで利用するデータをカスタムフックの戻り値にする
- コンポーネントからカスタムフックを呼び出す
以下ではそれぞれの手順について説明します。
コンポーネントのコードから分離させたいフックを検討する
コンポーネントからカスタムフックへ実装を移動させるフックの検討をします。コンポーネントから分離したほうがよいフックは以下の通りです。
- 処理が複雑なフック
- 複数のコンポーネントで同じ実装がされているフック
- データ取得に関する(Viewに関係しない)フック
関連するフックをカスタムフックへ移動する
分離したいフックの検討が終わったら、関連するフックをカスタムフックへ移動します。
今回は『Todoリストの取得』に関するフックをカスタムフックにしたいので、Todoリストを保存するuseState
とTodoリストを取得するuseEffect
を移動します。
App.tsx
- import axios from "axios";
- import { useEffect, useState } from "react";
- type TodoItem = {
- id: number;
- content: string;
- completed: boolean;
- };
const App = () => {
- const [todos, setTodos] = useState([] as TodoItem[]);
- useEffect(() => {
- const getTodoRequest = async () => {
- const response = await axios.get("http://localhost:4000/todos");
- const todos = response.data;
- return todos;
- };
- getTodoRequest().then((todos) => setTodos(todos as TodoItem[]));
- }, []);
return (
<>
<h2>TodoList</h2>
<ul>
{todos.map(({ id, content }) => (
<li key={id}>
<div>{content}</div>
</li>
))}
</ul>
</>
);
};
export default App;
src/lib/hooks/useTodos.ts
import axios from "axios";
import { useEffect, useState } from "react";
type TodoItem = {
id: number;
content: string;
completed: boolean;
};
const useTodos = () => {
const [todos, setTodos] = useState([] as TodoItem[]);
useEffect(() => {
const getTodoRequest = async () => {
const response = await axios.get("http://localhost:4000/todos");
const todos = response.data;
return todos;
};
getTodoRequest().then((todos) => setTodos(todos as TodoItem[]));
}, []);
};
export default useTodos;
コンポーネントで利用するデータをカスタムフックの戻り値にする
今回の場合、コンポーネントではTodoリストのデータを利用します。
ですので、カスタムフックの戻り値はTodoリストの保存されたオブジェクトにします。
src/lib/hooks/useTodos.ts
import axios from "axios";
import { useEffect, useState } from "react";
type TodoItem = {
id: number;
content: string;
completed: boolean;
};
const useTodos = () => {
const [todos, setTodos] = useState([] as TodoItem[]);
useEffect(() => {
const getTodoRequest = async () => {
const response = await axios.get("http://localhost:4000/todos");
const todos = response.data;
return todos;
};
getTodoRequest().then((todos) => setTodos(todos as TodoItem[]));
}, []);
+ return todos;
};
export default useTodos;
コンポーネントからカスタムフックを呼び出す
コンポーネントでカスタムフックをimport
し、カスタムフックの戻り値を変数で受け取ります。
あとは受け取った変数を利用してUIを構築すればOKです。
+ import useTodos from "./lib/hooks/useTodos";
const App = () => {
+ const todos = useTodos();
return (
<>
<h2>TodoList</h2>
<ul>
{todos.map(({ id, content }) => (
<li key={id}>
<div>{content}</div>
</li>
))}
</ul>
</>
);
};
export default App;
以上でカスタムフック導入後のコードが完成します。
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!