回到部落格
2024-02-23
【React作品集】Todo List專案 part.1

原文發表於 Medium。
今天開始新的系列文章 — 【React作品集】,希望帶著大家一步步建構起一個簡單可運行的React專案。本系列第一個主題是Todo list。
首先我們先建構起一個新的React專案,這邊使用vite:
npx create-vite
//專案取名todo
//架構選擇React+typeScript
接著把App.tsx的JSX return內容,以及App.css、index.css內容全部刪除(不要刪掉檔案喔!)。
頁面架構初擬
接下來在App.tsx中初步建構todo的架構:
//App.tsx
import "./App.css";
function App() {
return (
{/*主外框*/}
<div className="mainContainer">
{/*大標題*/}
<h1 className="title">我的Todo's</h1>
{/*待辦事項輸入欄位*/}
<div className="userInputContainer">
<input type="text" /> <button>OK</button>
</div>
{/*代辦事項列表*/}
<div className="todoItemsList">
{/*假的PlaceHolder*/}
<div className="todoItem">
<input type="checkbox" />
<p>Todo Item!!</p>
<button>刪除</button>
</div>
<div className="todoItem">
<input type="checkbox" />
<p>ToDo Item2!!</p>
<button>刪除</button>
</div>
</div>
</div>
);
}
export default App;
//App.css
.mainContainer {
width: 360px;
height: 500px;
margin: 20px auto;
padding: 30px;
display: flex;
flex-direction: column;
align-items: center;
background: #ffffff;
box-shadow: 2px 2px 5px #a79d9d;
}
.title {
width: 100%;
text-align: center;
margin-bottom: 0;
}
.userInputContainer {
width: 100%;
display: flex;
border-bottom: 1px #aeacac solid;
padding-bottom: 10px;
}
.userInputContainer input {
flex: 1;
}
.todoItemsList {
width: 100%;

Todo list的初步架構規劃
資料架構思考
通常在第一階段完畢之後,就要開始讓他有辦法動起來。我的習慣是先把需要呈現的資料結構想好。先在src資料夾內創立一個DUMMY_TODO.ts檔:
//DUMMY_TODO.ts
//項目的內容
export type TodoItem = {
timeStamp: string;
text: string;
checked: boolean;
};
//列表的內容,含UserID
export type TodoItemsList = {
userID: string;
todoList: TodoItem[] | [];
};
//假的Todo list資料,作為畫面呈現的測試使用。
export const DUMMY_TODO: TodoItemsList = {
userID: "user1",
todoList: [
{
timeStamp: "2024-02-23T08:00:00",
text: "買菜",
checked: false,
},
{
timeStamp: "2024-02-23T10:30:00",
text: "寫報告",
checked: false,
},
],
};
如果一開始就不使用TypeScript的話,直接使用:
//DUMMY_TODO.js
export const DUMMY_TODO = {
userID: "user1",
todoList: [
{
timeStamp: "2024-02-23T08:00:00",
text: "買菜",
checked: false,
},
{
timeStamp: "2024-02-23T10:30:00",
text: "寫報告",
checked: false,
},
],
};
我們就把它匯入到App.js中,並將內容渲染出來。:
import { useEffect, useState } from "react";
import "./App.css";
import { DUMMY_TODO, TodoItem } from "./DUMMY_DATA";
function App() {
const [todos, setTodos] = useState<TodoItem[] | []>([]);
{使用useEffect把todolist設為useState值中}
useEffect(() => {
setTodos(DUMMY_TODO.todoList);
}, []);
return (
<div className="mainContainer">
<h1 className="title">我的Todo's</h1>
<div className="userInputContainer">
<input type="text" /> <button>OK</button>
</div>
<div className="todoItemsList">
{/*渲染todo列表資料*/}
{todos.map((todo) => {
return (
<div className="todoItem" key={todo.timeStamp}>
<input type="checkbox" />
<p>{todo.text}</p>
<button>刪除</button>
</div>
);
})}
</div>
</div>
);
}
export default App;

有人可能會疑惑,為什麼要用useEffect呢?其實我只是為了未來fetch後端API或取用localStorage 會比較方便。
到這,我們這個專案的第一階段就完成了。接下來我們就真的要讓他動起來了,請看下一篇。