TypeScriptでReact Hooksの型指定を徹底解説!useStateとuseEffectの初心者ガイド
生徒
「ReactでuseStateを使っているのですが、TypeScriptだと型を指定しないといけないのでしょうか?」
先生
「そうですね。TypeScriptを使う大きなメリットは、データの種類をあらかじめ決めておくことで、プログラムのミスを未然に防げる点にあります。」
生徒
「初心者なので、どうやって型を書けばいいのか、具体的な書き方が知りたいです!」
先生
「それでは、useStateやuseEffectでの型指定の方法を、一から順番に学んでいきましょう!」
1. TypeScriptとReact Hooksの基本
まず最初に、TypeScriptとReact Hooksの関係について整理しておきましょう。TypeScriptとは、JavaScriptというプログラミング言語に「型」というルールを追加したものです。型とは、そのデータが「数値」なのか「文字」なのかを明確に区別するための名札のようなものです。パソコンを初めて触る方にとっては、データの種類を分ける箱のようなものだとイメージしてください。
そして、React Hooks(リアクトフック)とは、Reactという画面を作るための道具箱の中にある便利な機能のことです。代表的なものに、データを一時的に保存するuseStateや、画面が表示されたときに特定の動きをさせるuseEffectがあります。これらに型を指定することで、間違った種類のデータを入れようとしたときに、パソコンが事前に「それは間違いですよ」と教えてくれるようになります。
2. useStateの型指定の重要性
useStateは、画面上で変化するデータを管理するために使われます。例えば、ボタンを押した回数や、入力フォームに書かれた名前などです。TypeScriptを使わずにプログラムを書くと、数字を入れるはずの場所に間違えて文字を入れてしまっても、動かしてみるまで間違いに気づかないことがあります。
型指定を行うことで、プログラムを書いている最中にエラーを表示してくれます。これにより、開発の効率が劇的に上がり、バグと呼ばれるプログラムの不具合を減らすことができます。フロントエンド開発において、型を意識することは、建物を建てる際の設計図を正確に書くことと同じくらい重要です。
3. 数値や文字列を扱うuseStateの書き方
まずは最も基本的な、数値や文字列を扱う場合の書き方を見てみましょう。TypeScriptでは、useState<型名>という形式で、どのようなデータを扱うかを指定します。これをジェネリクスと呼びますが、今は「どの種類の箱を使うか指定する記号」だと考えてください。
以下の例では、カウンターの数字を管理するプログラムを書いています。ここでは「number(数値)」という型を指定しています。
import React, { useState } from 'react';
const CounterComponent = () => {
// useStateに <number> と書くことで、countは数値しか受け付けなくなります
const [count, setCount] = useState<number>(0);
const increment = () => {
setCount(count + 1);
};
return (
現在の回数: {count}
);
};
このように書くことで、もしsetCount("たくさん")のように文字を入れようとすると、TypeScriptがエラーを出して止めてくれます。
4. 型推論という便利な仕組み
実は、TypeScriptには型推論という非常に賢い機能があります。これは、最初に設定した初期値を見て、パソコンが自動的に型を予想してくれる仕組みです。例えば、useState(0)と書けば、わざわざ<number>と書かなくても、0が数値であることを理解して「この箱は数値用だね」と判断してくれます。
しかし、中身が空の状態から始まる場合や、複雑なデータを扱う場合は、省略せずに型を書くのが一般的です。初心者のうちは、練習のために明示的に型を記述することをおすすめします。明示的に書くことで、自分自身もどのようなデータを扱っているのか再確認できるからです。
5. オブジェクトを扱うuseStateの型指定
実際の開発では、単一の数字だけでなく、名前や年齢などの複数の情報をセットにしたオブジェクトを扱うことが多いです。この場合は、まずデータの構造を定義する「type」や「interface」というものを作成します。
例えば、ユーザー情報を管理する場合は、以下のように書きます。プログラミング未経験の方にとって、この「構造を決める」作業は、名簿の項目(氏名、生年月日など)を決める作業に似ています。
import React, { useState } from 'react';
// ユーザーのデータの形を定義します
type User = {
id: number;
name: string;
email: string;
};
const UserProfile = () => {
// useStateに先ほど作った <User> 型を指定します
// 最初はデータがないので null(何もない)を許容するように設定します
const [user, setUser] = useState<User | null>(null);
const login = () => {
setUser({
id: 1,
name: "山田太郎",
email: "yamada@example.com"
});
};
return (
{user ? (
こんにちは、{user.name}さん
) : (
)}
);
};
ここで出てきた| nullというのは、ユニオン型と呼ばれ、「User型のデータ、または、何もない状態(null)」のどちらかを受け入れるという意味です。最初はデータが入っていないので、このような書き方をよく使います。
6. 配列を管理するuseStateのコツ
次に、データのリスト、つまり配列を扱う方法です。例えば、買い物リストやToDoリストなどがこれに当たります。配列の型指定は、型名[]という書き方をします。
以下のプログラムは、文字列のリストを管理する例です。空の配列[]を初期値にする場合、TypeScriptは何の配列か判断できないため、必ず型を指定する必要があります。
import React, { useState } from 'react';
const TodoList = () => {
// 文字列(string)が複数入る配列であることを指定します
const [todos, setTodos] = useState<string[]>([]);
const addTodo = () => {
setTodos([...todos, "新しいタスク"]);
};
return (
{todos.map((todo, index) => (
- {todo}
))}
);
};
配列の型指定を忘れると、後でデータを取り出すときにパソコンが「この中身は何ですか?」と困ってしまうので、忘れずに指定しましょう。mapという命令は、配列の中身を一つずつ取り出して画面に表示するための便利な機能です。
7. useEffectの役割と型指定
useEffectは、コンポーネントが表示された瞬間や、データが更新されたタイミングで実行したい処理を記述する場所です。例えば、インターネットからデータを取得したり、画面上のタイマーを動かしたりするときに使います。
実は、useEffect自体にはuseStateのような複雑な型指定はあまり必要ありません。しかし、その中で使う関数の書き方や、クリーンアップ関数と呼ばれる「後片付け」の処理には注意が必要です。クリーンアップ関数とは、例えばタイマーを止めるなど、画面から消えるときに行う作業のことです。
8. データの取得とuseEffectの実践例
実際にインターネットから情報を取ってくる(フェッチする)ときの流れを確認しましょう。ここでは、取得したデータを保存するためのuseStateと、取得処理を行うuseEffectを組み合わせて使います。
import React, { useState, useEffect } from 'react';
type Post = {
id: number;
title: string;
};
const PostList = () => {
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
// データの取得を模した関数
const fetchData = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data: Post[] = await response.json();
setPosts(data);
};
fetchData();
// 最後に何も返さない(または関数を返す)のが基本です
}, []); // この[]は、最初の一回だけ実行するという意味です
return (
記事一覧
{posts.slice(0, 5).map(post => (
{post.title}
))}
);
};
asyncやawaitは、インターネット越しの通信など、時間がかかる処理を待つための魔法の言葉です。プログラミング未経験の方は、「データの準備ができるまでちょっと待ってね」という合図だと覚えておいてください。このように型をしっかり決めておくことで、取得したデータに何が含まれているかが一目でわかるようになります。
9. 初心者が陥りやすいエラーと対策
TypeScriptの学習を始めると、画面が赤文字のエラーだらけになることがあります。しかし、それは決して悪いことではありません。エラーメッセージは「ここを直せば完璧に動くよ」というパソコンからのアドバイスです。よくあるミスは、型を指定したのに違うデータを入れてしまうことです。例えば、数値を期待しているところに、誤って「"10"」という文字を渡してしまうケースです。
また、初期値をundefined(定義されていない)やnullにしておきながら、後でそのデータの中身にアクセスしようとするとエラーが出ます。これを防ぐには、事前に「データがあるかどうか」を確認する条件分岐(if文など)を入れることが大切です。これを型ガードと呼び、より安全なプログラムを作るための重要な技術です。
10. 型指定をマスターして次のステップへ
ここまで、useStateとuseEffectでの型指定の基本について解説してきました。一見すると、型を書くのは面倒に感じるかもしれません。しかし、大規模な開発やチームでの制作になると、この「型」があるおかげで、誰が読んでも理解しやすい、壊れにくいプログラムを作ることができます。初心者の皆さんは、まずは簡単な数値や文字列の型指定から始めて、少しずつオブジェクトや配列の型に慣れていってください。
ReactとTypeScriptの組み合わせは、現在のウェブ開発において非常に人気があり、習得することで作れるアプリの幅が大きく広がります。最初は難しい単語に戸惑うこともあるかと思いますが、一つずつ実際にコードを打ち込んで、エラーを出しながら学んでいくことが上達への近道です。焦らずに、自分のペースでプログラミングを楽しんでいきましょう。