回到部落格

2024-02-23

【React作品集】Todo List專案 part.1

【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 會比較方便。

到這,我們這個專案的第一階段就完成了。接下來我們就真的要讓他動起來了,請看下一篇。