【實作記錄】Todo List | React
簡介
這是一個有基本功能的 todo list 練習,為了練習語法以及邏輯,所以參考了教學影片,文末附上教學影片之連結。這裡練習了各個 Component 之間的傳遞、React Hook 也認識了之前沒有用過的幾個 CSS 小方法。下面詳細記錄了自己的學習步驟。
功能
- 增加 task
- 刪除 task
- 完成的 task : 打√, 劃掉的線
- 可以 filter 完成/未完成/所有的 task
前置作業
簡單劃分需要的功能以及元件。除了 index.js 外,主要的操作都在 App.js.其餘的 Component 集中放
到 components 的 file 中。
- index.js
- App.js
- Form.js
- TodoList.js
- Todo.js
步驟
基本設置
整個Todo list 是由兩個部分組成的:form 以及 list。
form : 設置讓用戶輸入的 form , 包含輸入的框框 (input) & 添加按鈕 (button) & filter (select) 。Filter 裡有三個 option : All/ completed / uncompleted。
list : 用戶在增加 task 之後,該 task 會出現在 list 裡。只要設置一個 unorder list,增加的部分之後會處理。
1 | import React from 'react'; |
1 | import React from "react" |
1 | import React from "react" |
處理用戶輸入的input
在 App.js 使用 useState 設定 value 的初始值。因為需要處理的 input在 Form.js 中,因此要把這兩個參數往下傳,之後才能在 Form.js 中引入。
1 | const [inputText, setInputText] = useState("")//初始值為空字串 |
接著處理用戶輸入的資訊。在 input 中設定 onchange
以及 value
. input 改變時,onChange
會被觸發,因而執行設定好的 function.
創造一個處理更新的 function : handlechange.使用 setTnputText 更新input 的 value
.用戶每輸入一個字,就會觸發 onchange
, 所以會出現下面的結果。
const Form = ({ setInputText })
相等於 const Form = ({props})
的寫法,前者是直接把 setInput 這個參數傳進來,所以在使用 setInputText 的時候不用加上 props. 後者在使用時要寫 props.setInputText
,直接把參數傳進來的寫法會比較簡潔。
1 | const Form = ({ inputText ,setInputText }) => { //這是App.js中傳進來的參數 |
結果會是這個樣子:
把用戶輸入的東西存進 todo list 裡
運作邏輯:用戶輸入 task > 按 summit button > task 被加到 list 裡
增加 button onclick
function. 在按下 button 之後,用戶輸入的值加到 todo list 裡,可以創造一個新的 hook 將 todo list 存進 array 裡。因此創造了const [todos, setTodos] = useState([])
,初始值為空 array.與input一樣,這個功能會在 Form.js 裡完成,因此也要將參數往下傳。
1 | const [todos, setTodos] = useState([]) |
接著處理用戶輸入的資料。在把 todos, setTodos 傳進 Form.js 後,增加button 的 onclick
,觸發 function 設為 submitHandleChange function. 這個 function 會更新 todos 這個 state,首先將原本就存在在 task 存進來,再增加用戶新輸入的 task. 用戶輸入的 task 會以 object 的形式傳進去,包括了 tasks 的名字 (text) 、是否完成 (completed:boolean)、id (使用亂數產生)。
1 | function submitHandleChange(e) { |
可以使用 react debugger 來看 todos 這個 state 的變化。在輸入 task 後按下 submit button, state 就會立刻更新。
把輸入的 tasks ( 更新後的 state ) 渲染到瀏覽器上
用戶輸入的 tasks 要加到 todo list 裡,這個部分要在 TodoList.js 進行。在 App.js 中把 todos 這個參數往下傳。
1 | < TodoList todos={todos}/> |
在 TodoList.js 裡,todos state 每一次更新,都要把資料往下傳到 todo.js 裡渲染。因此這裡使用 map() 遍歷 todos 裡的每一個 element ,除了輸入的 task 外,也要加上 key ,才不會報錯。
1 | const TodoList = ({todos}) => { |
資料往下傳到 Todo.js 後,就會按照設定好的樣式傳染到瀏覽器上。
1 | function Todo({text}) { |
增加刪除功能
有關 task 本 task 的處理,都在 Todo.js裡處理。刪除功能是直接操作 todos state, 因此會調用到 todos 以及 setTodos. 這兩個參數要從要從最頂層的 App.js 往下傳到 TodoList.js ,然後再往下傳到 Todo.js 中.
創造新的 function , 使用filter()來過濾掉不符合條件的 element. 這裡的條件設定為:todos state 中的 element 與 被點擊的 element 之 id 如果不相同就會被留下,相同就表示那是是用戶要刪掉的 element,因為不符合條件所以就被過濾掉了。
1 | function deleteHandleChange(){ |
增加 task completed 功能
創造新的 function , 使用 map() 遍歷 todos state, 如果 element id 等於被點擊的 item 的 id,就將該 element 的 completed 的 boolean 改成相反的。最後再返回該item.
1 | function CompleteHandleChange(){ |
接著處理 UI 的部分,完成後會顯示打打勾、一槓、灰色字。可以用 todo.complete 來判斷是否要加入某個className.
1 | //打勾勾 |
1 | //一槓、灰色字 |
製作 filter 功能 (All / Complete / Uncomplete)
先創造一個 status state 來儲存點擊 option 後的結果。這個 state 會在 Form 中處理,因此要把參數往下傳。
1 | //把setStatus往下傳,會在 form.js 處理 |
因為選單在 Form.js 裡,因此在 Form.js 處理。設定選單改變時要執行的 function : 更新 setStatus 成點選的選項。選擇 complete的話,這裡 setStatus 就會更新為 completed.
1 | function statusHandleChange(event){ |
再創造一個 filtered state 來儲存被加進來的 task。創造一個新的 state 是為了不要影響到原本用來儲存 tasks 的 todos state. 過濾後的tasks 會被儲存在這個 state.
1 | //會在 Todolish.js 中處理 |
接著設定 filter 的條件,這裡使用 switch() 來處理 All/completed/uncompleted 的情況。
1 | function filterHandlerChange(){ |
FilteredTodos 會在 tasks 存進 todos state 以及 option 被選擇的時候更新。使用 useEffect 來設定當上述兩種情況發生時,FilteredTodos 執行 function filterHandlerChange。
1 | useEffect(() => { |
小結
到這裡,基本的增、刪、過濾功能就已經完成了。當中遇到無法成功渲染的多數原因為,沒有將參數往下傳到各個 Component 中,在這次的練習中深刻體現要了解自己寫的每一行程式碼的意思,出錯了才有辦法找到 bug 在哪裡。經過這次練習,對拆分的 component 間要如何傳遞以及 React 的寫法都比較熟悉了一些。希望下一個練習可以挑戰更複雜的(堅定臉。
由於主要目的是熟悉 React 的寫法,界面就沒有弄得很 fancy ,就讓他陽春陽春的XD
如果有任何不對的地方/有更好的寫法,再麻煩各位大大指教! :)
參考資料
Build A Todo App With REACT | React Project For Beginners (FULL).