ReactでシンプルなTodoアプリを作成する
目的
- Reactについて理解を深めたい
- TypeScriptについて理解を深めたい
- 定期的に自分のコードを見直す為に何か更新できるアプリを作りたい
- AIにコード生成を頼らない(リファクタリングに使うのは可)
以上の理由から比較的シンプルで尚且つ拡張しようと思えばかなり幅広くアップデートができると感じ作成しました。
その為こちらの記事も大きな更新が発生した際は更新する予定です。
使用技術
フロントエンド
バックエンド
コンポーネント設計
Todo list V.1として以下のような必要最低限の要素での実装です。
- 自身の名前を記載したHeader
- Todoの内容と追加するためのSubmit button
- 追加された要素を表示するTodo list
├── components
├── Header
│ └── Header.tsx
├── TodoForm
│ └── TodoForm.tsx
├── TodoList
│ └── TodoList.tsx
└── index.ts
以上のような設計にしました。
初学者の為あまり他の人の設計を真似するのはどうなのかと思い一旦思いつきのまま実装します。
実装の流れ(下準備)
Todo Form
まずはTodoForm
にTodoの要素であるinput要素と要素をTodoList
に追加するためのbutton要素を追加します。
import React from "react";
// style
import { Input } from "@chakra-ui/input";
import { Button } from "@chakra-ui/button";
export const TodoForm: React.FC = () => {
return (
<>
<Input placeholder="Todo title" />
<Button color="#81A1C1">Add todo</Button>
</>
);
};
Todo List
現状は要素を追加する機能が無いのでサンプルのデータを直接書いています。
import React from "react";
// style
import { UnorderedList, ListItem, Box } from "@chakra-ui/layout";
export const TodoList: React.FC = () => {
return (
<Box>
<UnorderedList margin={"auto"} width={"fit-content"}>
<ListItem>Learning english</ListItem>
<ListItem>Lunch with friend</ListItem>
<ListItem>Booking train</ListItem>
<ListItem>Shopping</ListItem>
</UnorderedList>
</Box>
);
};
デザインは苦手なので不恰好ですがその内綺麗に整えたいです(誰か...)
機能の実装編
それでは下準備があらかた終了したので実際にinput
要素に入力した内容をbutton
を押すことでList
に追加される機能を実装していきます。
inputの処理
input
要素に入力された内容をList
に追加する為に保持する必要があります。
その時に使うのがuseState
というものです。
// hooks
const [todoTitle, setTodoTitle] = useState();
// handler
const handleTodoTitleChange = (event: any) => {
setTodoTitle(event.target.value);
};
<Input placeholder={"Todo title"} onChange={handleTodoTitleChange} />
状態を管理するuseState
と入力された値を親コンポーネントに渡すためにProps
を使います。
// interface
interface TodoTitleProps {
onTodoTitleChange: (todoTitle: string) => void;
}
export const TodoForm: React.FC<TodoTitleProps> = ({ onTodoTitleChange }) => {
// hooks
const [todoTitle, setTodoTitle] = useState("");
// handler
const handleTodoTitleChange = (event: any) => {
setTodoTitle(event.target.value);
};
// onClick
const onAddTodo = () => {
onTodoTitleChange(todoTitle);
setTodoTitle("");
console.log("button click");
};
return (
<HStack alignItems={"center"} width={"auto"} justifyContent={"center"}>
<Input
placeholder={"Todo title"}
onChange={handleTodoTitleChange}
value={todoTitle}
/>
<Button color="#81A1C1" onClick={onAddTodo}>
Add todo
</Button>
</HStack>
);
};
Propsの受け取りと受け渡し
今回であればTodoForm
コンポーネントで入力されたテキストを親コンポーネンであるApp
に渡し、親コンポーネンで別の子コンポーネントであるTodoList
コンポーネントに渡します。
// import component
import { Header, TodoForm, TodoList } from "./components/";
import { useState } from "react";
function App() {
// hooks
const [todoTitle, setTodoTitle] = useState("");
// handler
const handleTodoTitleChange = (todoTitle: string) => {
setTodoTitle(todoTitle);
};
return (
<>
<Header />
<TodoForm onTodoTitleChange={handleTodoTitleChange} />
<TodoList todoTitle={todoTitle} />
</>
);
}
export default App;
TodoList
コンポーネントでは送られたProps
を受け取り表示します。
import React from "react";
// style
import { UnorderedList, ListItem, Box } from "@chakra-ui/layout";
// interface
interface todoTitleProps {
todoTitle: string;
}
export const TodoList: React.FC<todoTitleProps> = ({ todoTitle }) => {
return (
<Box>
<UnorderedList margin={"auto"} width={"fit-content"}>
<ListItem>{todoTitle}</ListItem>
</UnorderedList>
</Box>
);
};
これで表示は出来ましたが、一つ入力しまた新たに入力した場合前回の内容が書き変わってしまうので受け取った内容を配列に格納しましょう。
export const TodoList: React.FC<todoTitleProps> = ({ todoTitle }) => {
// hooks
const [todoList, setTodoList] = useState<string[]>([]);
// function
const addTodo = () => {
setTodoList((prevTodoList) => [...prevTodoList, todoTitle]);
};
// useEffect
React.useEffect(() => {
if (todoTitle !== "") {
addTodo();
}
}, [todoTitle]);
return (
<Box>
<UnorderedList margin={"auto"} width={"fit-content"}>
{todoList.map((item, index) => (
<ListItem key={index}>{item}</ListItem>
))}
</UnorderedList>
</Box>
);
};
Props
として渡されたTodoTitle
をuseEffect
を使って受け渡される度にtodoList
配列に格納するようにしました。
useEffect内のifは初回レンダリングが発生し空の配列が作成されてしまうのでそれを回避する為です
一旦終わり
必要最低限の
- Todoの内容を入力
- 入力された内容がリストで表示される
以上の内容が出来ました。これからもっと拡張していきます。
figmaに書いたのにチェックボックスの実装が出来ていない。。次回の更新で追加予定
お願い
ソースコードはこちらに公開しています。
- 導入すべき機能
- デザインのアドバイス
- ソースコードのリファクタリング
- 変数や関数など命名の指摘
などなど自分でも改善していきますがまだまだReactを理解出来ていない部分が多いのでご指摘いただければ幸いです。Issues
にて管理していきますのでどんどん書き込んで下さい。
Discussion