参考にした記事
上記の記事では、ReactにJavascriptを使っていたが今回はTypeScriptを使ってみます。
Todoの型定義を作成し、useState に正しい型を明示的に指定します。
Go側のTodo構造体に対応するTypeScript型は以下のようになります(gorm.Model には ID, CreatedAt, UpdatedAt, DeletedAt などが含まれていますが、ここでは ID のみ使用しているので、それだけ型定義しておけばOKです)。
App.tsx
import { useEffect, useState } from "react";
import axios from "axios";
const API_URL = "http://localhost:8080/todos";
// ✅ Todo型を定義する
type Todo = {
ID:number;
title:string;
completed:boolean;
}
export default function App() {
// ✅ useStateに型を明示する
const [todos, setTodos] = useState<Todo[]>([]);
const [title, setTitle] = useState("");
useEffect(() => {
axios.get(API_URL).then((res) => setTodos(res.data));
}, []);
const addTodo = async () => {
const res = await axios.post(API_URL, { title });
setTodos([...todos, res.data]);
setTitle("");
};
const toggleTodo = async (id:number) => {
const res = await axios.put(`${API_URL}/${id}`);
setTodos(todos.map((t) => (t.ID === id ? res.data : t)));
};
const deleteTodo = async (id:number) => {
await axios.delete(`${API_URL}/${id}`);
setTodos(todos.filter((t) => t.ID !== id));
};
return (
<div style={{ maxWidth: 400, margin: "auto" }}>
<h1>Todo List</h1>
<input value={title} onChange={(e) => setTitle(e.target.value)} />
<button onClick={addTodo}>追加</button>
<ul>
{todos.map((todo) => (
<li key={todo.ID}>
<span
onClick={() => toggleTodo(todo.ID)}
style={{
textDecoration: todo.completed ? "line-through" : "none",
cursor: "pointer",
}}
>
{todo.title}
</span>
<button onClick={() => deleteTodo(todo.ID)}>削除</button>
</li>
))}
</ul>
</div>
);
}