React初心者がReact+TypeScriptについて勉強した時のメモです。
型がないせいでバグっている例
ボタンを押したらJSONPlaceholderのTodoのデータをaxiosを使ってデータ取得するプログラム。
https://jsonplaceholder.typicode.com/todos
App.tsx
import axios from "axios";
import { useState } from "react";
import { Todo } from "./Todo";
export default function App() {
const [todos, setTodos] = useState<any>([]);
const onClickFetchData = () => {
axios.get("https://jsonplaceholder.typicode.com/todos").then((res) => {
setTodos(res.data);
console.log(res);
});
};
return (
<div className="App">
<button onClick={onClickFetchData}>データ取得</button>
{todos.map((todo) => (
<Todo title={todo.title} userid={todo.userid} />
))}
</div>
);
}
Todo.tsx
export const Todo = (props) => {
const { title, userid } = props;
return <p>{`${title}(ユーザー:${userid})`}</p>;
};
データ取得したらユーザー名がundefinedになるというバグが発生している。
取得データに型を定義する
App.tsx
import axios from "axios";
import { useState } from "react";
import { Todo } from "./Todo";
type TodoType = {
userId: number;
id: number;
title: string;
completed: boolean;
};
export default function App() {
const [todos, setTodos] = useState<Array<TodoType>>([]);
const onClickFetchData = () => {
axios
.get<Array<TodoType>>("https://jsonplaceholder.typicode.com/todos")
.then((res) => {
setTodos(res.data);
});
};
return (
<div className="App">
<button onClick={onClickFetchData}>データ取得</button>
{todos.map((todo) => (
<Todo key={todo.id} title={todo.title} userid={todo.userId} />
))}
</div>
);
}
取得するデータにtype
として型を定義する。
axiosのget部分とuseStateの部分に取得データの型を当てることエディターの補完も効くようになりどこが間違っているかが分かる。
今回の場合は、以下の部分のuserid
のiが小文字になっていたからというのが分かった。
<Todo title={todo.title} userid={todo.userid} />
propsに型定義
type TodoType = {
userId: number;
title: string;
};
export const Todo = (props: TodoType) => {
const { title, userId } = props;
return <p>{`${title}(ユーザー:${userId})`}</p>;
};
propsも同様に型を定義しておくことでi
の小文字に気づけバグを防げる。
PickとOmit
型定義の部分(今回でいうTodoType
)を切り出した場合に型を呼び出す際にPick
かOmitを使うことで効率的に管理できる。
- 切り出したTodoType
types/todo.ts
export type TodoType = {
userId: number;
id: number;
title: string;
completed: boolean;
};
- Pick(抽出)
import { TodoType } from "./types/todo"
export const Todo = (props: Pick<TodoType, "userId" | "title">) => {
const { title, userId } = props;
return <p>{`${title}(ユーザー:${userId})`}</p>;
};
Pick
を使うことでこのコンポーネントで必要な型の情報のみ抜き出せる。
- Omit(省略)
import { TodoType } from "./types/todo"
export const Todo = (props: Omit<TodoType, "id" | "completed">) => {
const { title, userId } = props;
return <p>{`${title}(ユーザー:${userId})`}</p>;
};
Omit
はPick
の逆でTodoType
の中から必要ないものを除いた形。
コンポーネント自体の型
export const Todo: FC<Pick<TodoType, "userId" | "title">> = (props) => {
const { title, userId } = props;
return <p>{`${title}(ユーザー:${userId})`}</p>;
};
関数コンポーネント自体の型定義。