使用React和Material-UI構建TODO應用的前端UI
- 引言
- 環境準備
- 代碼解析
- 1. 導入必要的模塊
- 2. 創建React組件
- 3. 定義函數
- 3.1 獲取TODO列表
- 3.2 創建TODO項
- 3.3 更新TODO項
- 3.4 刪除TODO項
- 3.5 處理編輯點擊事件
- 3.6 關閉編輯對話框
- 3.7 保存編輯內容
- 4. 使用Effect鉤子
- 5. 渲染組件
- 功能實現
- 優化建議
- 總結
引言
在現代Web開發中,TODO列表應用是一個經典的示例,用于展示如何使用前端技術構建一個簡單的任務管理工具。本文將詳細介紹如何使用React框架和Material-UI庫來構建一個TODO列表應用,并解釋代碼的各個部分,幫助讀者理解其工作原理。
后端API請參考,使用Express.js和SQLite3構建簡單TODO應用的后端API
環境準備
在開始之前,請確保你已經安裝了以下工具和庫:
- Node.js:確保你已經安裝了Node.js,可以從Node.js官網下載并安裝。
- npm:Node.js的包管理工具,隨Node.js一起安裝。
- React:一個用于構建用戶界面的JavaScript庫,可以通過npm安裝。
- Material-UI:一個基于Material Design的React組件庫,同樣可以通過npm安裝。
- axios:一個基于Promise的HTTP客戶端,用于處理API請求。
安裝所需的依賴:
npm install react @mui/material @emotion/react @emotion/styled axios
代碼解析
讓我們逐步分析代碼,理解每個部分的功能。
1. 導入必要的模塊
import { useState, useEffect } from 'react';
import axios from 'axios';
import {TextField,Button,Checkbox,List,ListItem,ListItemText,IconButton,Dialog,DialogTitle,DialogContent,DialogActions,FormControlLabel
} from '@mui/material';
import { Delete, Edit } from '@mui/icons-material';
import { Todo } from '../types/todo';
- React:導入
useState
和useEffect
鉤子,用于狀態管理和副作用處理。 - axios:用于發送HTTP請求。
- Material-UI:導入各種組件,如文本框、按鈕、列表、對話框等。
- Icons:導入刪除和編輯圖標。
- Todo類型:定義TODO項的類型,確保數據的類型安全。
2. 創建React組件
export default function TodoList() {const [todos, setTodos] = useState<Todo[]>([]);const [searchTerm, setSearchTerm] = useState('');const [newTodo, setNewTodo] = useState({ title: '', description: '' });const [editingTodo, setEditingTodo] = useState<Todo | null>(null);const [editForm, setEditForm] = useState({ title: '', description: '', completed: false });
- todos:存儲TODO列表的狀態。
- searchTerm:存儲搜索詞的狀態。
- newTodo:存儲新TODO項的狀態。
- editingTodo:存儲正在編輯的TODO項的狀態。
- editForm:存儲編輯表單的狀態。
3. 定義函數
3.1 獲取TODO列表
const fetchTodos = async () => {try {const response = await axios.get(`http://localhost:3002/api/todos?q=${searchTerm}`);setTodos(response.data);} catch (error) {console.error('Error fetching todos:', error);}
};
- 功能:從后端獲取TODO列表,支持搜索功能。
- 實現:使用
axios.get
發送GET請求,根據searchTerm
進行模糊搜索。
3.2 創建TODO項
const createTodo = async () => {if (!newTodo.title.trim()) return;try {await axios.post('http://localhost:3002/api/todos', newTodo);setNewTodo({ title: '', description: '' });fetchTodos();} catch (error) {console.error('Error creating todo:', error);}
};
- 功能:創建一個新的TODO項。
- 實現:檢查標題是否為空,使用
axios.post
發送POST請求,創建成功后清空表單并刷新列表。
3.3 更新TODO項
const updateTodo = async (todo: Todo, isToggleComplete = false) => {try {const updatedTodo = isToggleComplete? { ...todo, completed: !todo.completed }: { ...todo, title: editForm.title, description: editForm.description, completed: editForm.completed };await axios.put(`http://localhost:3002/api/todos/${todo.id}`, updatedTodo);setEditingTodo(null);fetchTodos();} catch (error) {console.error('Error updating todo:', error);}
};
- 功能:更新TODO項,支持標記完成和編輯內容。
- 實現:根據
isToggleComplete
決定是更新完成狀態還是編輯內容,使用axios.put
發送PUT請求。
3.4 刪除TODO項
const deleteTodo = async (id: number) => {try {await axios.delete(`http://localhost:3002/api/todos/${id}`);fetchTodos();} catch (error) {console.error('Error deleting todo:', error);}
};
- 功能:刪除指定的TODO項。
- 實現:使用
axios.delete
發送DELETE請求,刪除成功后刷新列表。
3.5 處理編輯點擊事件
const handleEditClick = (todo: Todo) => {setEditingTodo(todo);setEditForm({title: todo.title,description: todo.description || '',completed: todo.completed});
};
- 功能:打開編輯對話框,填充TODO項的詳細信息。
- 實現:設置
editingTodo
和editForm
狀態,顯示編輯表單。
3.6 關閉編輯對話框
const handleClose = () => {setEditingTodo(null);setEditForm({ title: '', description: '', completed: false });
};
- 功能:關閉編輯對話框,重置表單。
- 實現:清除
editingTodo
和editForm
狀態。
3.7 保存編輯內容
const handleSave = () => {if (editingTodo && editForm.title.trim()) {updateTodo(editingTodo);}
};
- 功能:保存編輯的內容。
- 實現:檢查標題是否為空,調用
updateTodo
更新TODO項。
4. 使用Effect鉤子
useEffect(() => {const debounceSearch = setTimeout(() => {fetchTodos();}, 300);return () => clearTimeout(debounceSearch);
}, [searchTerm]);
- 功能:實現搜索的防抖動效果,防止頻繁請求。
- 實現:使用
setTimeout
延遲300毫秒后執行fetchTodos
,并在組件銷毀時清除定時器。
5. 渲染組件
return (<div style={{ maxWidth: 600, margin: '0 auto', padding: '20px' }}><TextFieldfullWidthlabel="Search Todos"variant="outlined"value={searchTerm}onChange={(e) => setSearchTerm(e.target.value)}margin="normal"/><List>{todos.map((todo) => (<ListItemkey={todo.id}secondaryAction={(<><IconButton onClick={() => handleEditClick(todo)}><Edit /></IconButton><IconButton onClick={() => deleteTodo(todo.id)}><Delete /></IconButton></>)}style={{display: todo.completed ? 'none' : 'flex',opacity: todo.completed ? 0.7 : 1}}><Checkboxchecked={Boolean(todo.completed)}onChange={() => updateTodo(todo, true)}/><ListItemTextprimary={todo.title}secondary={todo.description}style={{textDecoration: todo.completed ? 'line-through' : 'none',}}/></ListItem>))}</List><div style={{ display: 'flex', gap: 10, marginBottom: 20 }}><TextFieldfullWidthlabel="New Todo Title"value={newTodo.title}onChange={(e) => setNewTodo({ ...newTodo, title: e.target.value })}/><TextFieldfullWidthlabel="Description"value={newTodo.description}onChange={(e) => setNewTodo({ ...newTodo, description: e.target.value })}/><Buttonvariant="contained"color="primary"onClick={createTodo}>Add</Button></div><Dialog open={Boolean(editingTodo)} onClose={handleClose}><DialogTitle>Edit Todo</DialogTitle><DialogContent><TextFieldautoFocusmargin="dense"label="Title"fullWidthvalue={editForm.title}onChange={(e) => setEditForm({ ...editForm, title: e.target.value })}/><TextFieldmargin="dense"label="Description"fullWidthmultilinerows={3}value={editForm.description}onChange={(e) => setEditForm({ ...editForm, description: e.target.value })}/><FormControlLabelcontrol={(<Checkboxchecked={editForm.completed}onChange={(e) => setEditForm({ ...editForm, completed: e.target.checked })}/>)}label="Completed"/></DialogContent><DialogActions><Button onClick={handleClose} color="primary">Cancel</Button><ButtononClick={handleSave}color="primary"disabled={!editForm.title.trim()}>Save</Button></DialogActions></Dialog></div>
);
- 搜索框:允許用戶輸入搜索詞,實時搜索TODO列表。
- TODO列表:顯示所有TODO項,每個項包含標題、描述、編輯和刪除按鈕,以及完成狀態Checkbox。
- 添加TODO表單:允許用戶輸入新TODO的標題和描述,點擊“Add”按鈕創建。
- 編輯對話框:當用戶點擊編輯按鈕時,顯示編輯表單,允許修改TODO的標題、描述和完成狀態。
功能實現
- 添加TODO項:用戶輸入標題和描述后,點擊“Add”按鈕,發送POST請求到后端,創建新的TODO項。
- 編輯TODO項:用戶點擊編輯按鈕,打開編輯對話框,修改TODO項的詳細信息后,點擊“Save”按鈕,發送PUT請求到后端,更新TODO項。
- 刪除TODO項:用戶點擊刪除按鈕,發送DELETE請求到后端,刪除指定的TODO項。
- 搜索TODO項:用戶輸入搜索詞,組件會自動搜索標題或描述中包含該詞的TODO項,支持防抖動功能,減少請求次數。
- 標記完成:用戶點擊Checkbox,TODO項會被標記為完成,樣式會變為灰色并添加刪除線。
優化建議
盡管這段代碼已經可以正常工作,但為了提升應用的性能和用戶體驗,可以考慮以下優化:
- 添加加載狀態:在數據加載過程中,顯示加載動畫,提升用戶體驗。
- 添加錯誤提示:在請求失敗時,顯示錯誤提示信息,幫助用戶了解問題所在。
- 添加成功提示:在創建、更新或刪除TODO項成功后,顯示成功提示信息。
- 優化樣式:根據Material Design規范,優化組件的樣式和布局,提升視覺效果。
- 添加響應式設計:確保應用在不同設備上都能良好顯示,提升應用的適應性。
- 添加數據驗證:在前端和后端都添加數據驗證,確保輸入的數據合法有效。
總結
通過本文,我們詳細解析了一個使用React和Material-UI構建的TODO列表應用。從狀態管理、HTTP請求到組件渲染,每個部分都進行了詳細的解釋。希望這篇文章能夠幫助讀者理解如何使用這些技術構建一個簡單的TODO應用,并為進一步的學習和開發打下基礎。