🌍
React(ts) で Todoアプリを作ってみた
react setup
npx create-react-app react-todo-ts --template typescript
cd react-todo-ts
yarn start
todo アプリ作成
まず、最初にtypes.tsを作成
intertfaceを用いて'Todo'という型を定義しています。
interface: 新しい方を定義する。(Todo)
export interface Todo{
id: number;
text: string;
completed: boolean;
}
export default Todo;
App.tsx
まずApp.tsxにtodoの処理や画面を書きます。
import React, { useState } from 'react';
import './App.css';
import {Todo} from './types';
import AddTodo from './AddTodo';
import TodoList from './TodoList';
const App: React.FC = () => {
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: 'Learn React with TypeScript', completed: false },
])
const addTodo = (text: string) => {
setTodos([...todos, { id: todos.length + 1, text, completed: false }]);
};
const toggleTodo = (id: number) => {
setTodos(
todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};
return (
<div className="App">
<h1>Todo App</h1>
<AddTodo addTodo={addTodo} />
<TodoList todos={todos} toggleTodo={toggleTodo} />
</div>
);
}
export default App;
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: 'Learn React with TypeScript', completed: false },
])
Reactのフックである、ローカルステートを管理するために使用します。
また、Todo[]はTypeScriptのジェネリクスでtodo型がtodoオブジェクトの配列と指定
const toggleTodo = (id: number) => {
setTodos(
todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};
こちらはcheckboxがクリックされた時に反応する関数です。
クリックされたtodoをmap関数で一致するidを探す、見つけたcompletedを反転させます。
次にレンダリングされてるAddTodo.tsxを作成します。
AddTodo.tsx
// AddTodo.tsx
import React, { useState, FC } from 'react';
interface AddTodoProps {
addTodo: (text: string) => void;
}
const AddTodo: FC<AddTodoProps> = ({ addTodo }) => {
const [text, setText] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
addTodo(text);
setText('');
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={text}
onChange={e => setText(e.currentTarget.value)}
/>
<button type="submit">Add Todo</button>
</form>
);
};
export default AddTodo;
interface AddTodoProps {
addTodo: (text: string) => void;
}
AddTodoコンポーネントに渡されるpropsの型を定義します。
この場合はstringになります。
const AddTodo: FC<AddTodoProps> = ({ addTodo }) => {
};
FC<AddTodoProps>でAddTodoという名前の関数コンポーネントを定義しpropsの型が先ほど宣言したInteferfaceとしています。
{{add Todo}}ではデストラクチャリングを使用して、propsからaddTodo関数を抽出する。
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={text}
onChange={e => setText(e.currentTarget.value)}
/>
<button type="submit">Add Todo</button>
</form>
);
formで送信するとhandleSubmit関数が呼び出されます。
次にTodoList.tsx になります。
TodoList.tsx
// TodoList.tsx
import React, { FC } from 'react';
import TodoItem from './TodoItem';
import { Todo } from './types';
interface TodoListProps {
todos: Todo[];
toggleTodo: (id: number) => void;
}
const TodoList: FC<TodoListProps> = ({ todos, toggleTodo }) => {
return (
<ul>
{todos.map(todo => (
<TodoItem key={todo.id} {...todo} toggleTodo={toggleTodo} />
))}
</ul>
);
};
export default TodoList;
AddTodo.tsxと同じようにInterfaceを作ります。
interface TodoListProps {
todos: Todo[];
toggleTodo: (id: number) => void;
}
```
AddTodoの方で解説してるので、ここは省きます。
次にコンポーネントになります。
```
const TodoList: FC<TodoListProps> = ({ todos, toggleTodo }) => {
return (
<ul>
{todos.map(todo => (
<TodoItem key={todo.id} {...todo} toggleTodo={toggleTodo} />
))}
</ul>
);
};
ここはulの要素の中でtodos配列をmapでループしています。
各ループでTodoItemコンポーネントをレンダリングしてその各todoオブジェクトをpropsとして渡します。
TodoItem.tsx
// TodoItem.tsx
import React, { FC } from 'react';
import { Todo } from './types';
interface TodoItemProps extends Todo {
toggleTodo: (id: number) => void;
}
const TodoItem: FC<TodoItemProps> = ({ id, text, completed, toggleTodo }) => {
return (
<li>
<input
type="checkbox"
checked={completed}
onChange={() => toggleTodo(id)}
/>
{text}
</li>
);
};
export default TodoItem;
Discussion