好的, 我们来详细规划第 4 部分: 前端基础结构。我们将这部分分为 3 天, 每天专注于特定的前端基础组件和功能。
第 4 部分:前端基础结构 (3 天)
Day 1: 项目设置和基础组件
-
初始化项目 使用 Create React App 或 Vite 创建新的 React 项目:
npm create vite@latest lightweight-todo-pro -- --template react-ts cd lightweight-todo-pro npm install -
安装必要的依赖
npm install react-router-dom @mantine/core @mantine/hooks @mantine/form @mantine/notifications @tabler/icons-react -
设置基础布局组件 在
src/components/Layout.tsx中:import React from 'react'; import { AppShell, Header, Navbar, Text } from '@mantine/core'; import { Outlet } from 'react-router-dom'; export const Layout: React.FC = () => { return ( <AppShell padding="md" navbar={<Navbar width={{ base: 300 }} p="xs">{/* Navbar content */}</Navbar>} header={<Header height={60} p="xs"><Text>LightweightTodo Pro</Text></Header>} > <Outlet /> </AppShell> ); }; -
创建基础路由 在
src/App.tsx中:import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { MantineProvider } from '@mantine/core'; import { Layout } from './components/Layout'; import { Home } from './pages/Home'; import { Login } from './pages/Login'; import { Register } from './pages/Register'; const App: React.FC = () => { return ( <MantineProvider withGlobalStyles withNormalizeCSS> <Router> <Routes> <Route path="/" element={<Layout />}> <Route index element={<Home />} /> <Route path="login" element={<Login />} /> <Route path="register" element={<Register />} /> </Route> </Routes> </Router> </MantineProvider> ); }; export default App; -
创建占位页面组件 创建
src/pages/Home.tsx,src/pages/Login.tsx, 和src/pages/Register.tsx,暂时用简单的内容填充。
Day 2: 状态管理和 API 集成
-
设置状态管理 使用 React Context API 创建一个简单的状态管理系统。在
src/context/AuthContext.tsx中:import React, { createContext, useState, useContext, useEffect } from 'react'; interface AuthContextType { user: any | null; login: (userData: any) => void; logout: () => void; } const AuthContext = createContext<AuthContextType | undefined>(undefined); export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [user, setUser] = useState<any | null>(null); useEffect(() => { // 从本地存储中检查用户会话 const storedUser = localStorage.getItem('user'); if (storedUser) { setUser(JSON.parse(storedUser)); } }, []); const login = (userData: any) => { setUser(userData); localStorage.setItem('user', JSON.stringify(userData)); }; const logout = () => { setUser(null); localStorage.removeItem('user'); }; return ( <AuthContext.Provider value={{ user, login, logout }}> {children} </AuthContext.Provider> ); }; export const useAuth = () => { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }; -
创建 API 服务 在
src/services/api.ts中:import axios from 'axios'; const API_URL = 'http://localhost:3000/api'; const api = axios.create({ baseURL: API_URL, withCredentials: true, }); export const login = (email: string, password: string) => api.post('/auth/login', { email, password }); export const register = (username: string, email: string, password: string) => api.post('/auth/register', { username, email, password }); export const logout = () => api.post('/auth/logout'); export const getTodos = () => api.get('/todos'); export const createTodo = (todo: any) => api.post('/todos', todo); export const updateTodo = (id: string, todo: any) => api.put(`/todos/${id}`, todo); export const deleteTodo = (id: string) => api.delete(`/todos/${id}`); export default api; -
实现登录和注册功能 更新
src/pages/Login.tsx和src/pages/Register.tsx,使用 API 服务和 AuthContext。
Day 3: Todo 列表和表单组件
-
创建 Todo 列表组件 在
src/components/TodoList.tsx中:import React, { useEffect, useState } from 'react'; import { Table, Button, Group } from '@mantine/core'; import { getTodos, deleteTodo } from '../services/api'; export const TodoList: React.FC = () => { const [todos, setTodos] = useState([]); useEffect(() => { fetchTodos(); }, []); const fetchTodos = async () => { try { const response = await getTodos(); setTodos(response.data); } catch (error) { console.error('Failed to fetch todos', error); } }; const handleDelete = async (id: string) => { try { await deleteTodo(id); fetchTodos(); } catch (error) { console.error('Failed to delete todo', error); } }; return ( <Table> <thead> <tr> <th>Title</th> <th>Description</th> <th>Actions</th> </tr> </thead> <tbody> {todos.map((todo: any) => ( <tr key={todo.id}> <td>{todo.title}</td> <td>{todo.description}</td> <td> <Group> <Button color="blue">Edit</Button> <Button color="red" onClick={() => handleDelete(todo.id)}>Delete</Button> </Group> </td> </tr> ))} </tbody> </Table> ); }; -
创建 Todo 表单组件 在
src/components/TodoForm.tsx中:import React from 'react'; import { useForm } from '@mantine/form'; import { TextInput, Textarea, Button, Box } from '@mantine/core'; import { createTodo } from '../services/api'; export const TodoForm: React.FC = () => { const form = useForm({ initialValues: { title: '', description: '', }, }); const handleSubmit = async (values: any) => { try { await createTodo(values); form.reset(); // 可以在这里添加一个回调函数来刷新Todo列表 } catch (error) { console.error('Failed to create todo', error); } }; return ( <Box mx="auto"> <form onSubmit={form.onSubmit(handleSubmit)}> <TextInput required label="Title" placeholder="Enter todo title" {...form.getInputProps('title')} /> <Textarea mt="md" label="Description" placeholder="Enter todo description" {...form.getInputProps('description')} /> <Button type="submit" mt="md"> Add Todo </Button> </form> </Box> ); }; -
整合到主页 更新
src/pages/Home.tsx:import React from 'react'; import { Container, Title } from '@mantine/core'; import { TodoList } from '../components/TodoList'; import { TodoForm } from '../components/TodoForm'; export const Home: React.FC = () => { return ( <Container> <Title order={2}>My Todos</Title> <TodoForm /> <TodoList /> </Container> ); }; -
添加导航组件 在
src/components/Navigation.tsx中:import React from 'react'; import { Link } from 'react-router-dom'; import { Button, Group } from '@mantine/core'; import { useAuth } from '../context/AuthContext'; export const Navigation: React.FC = () => { const { user, logout } = useAuth(); return ( <Group> {user ? ( <> <Button component={Link} to="/">Home</Button> <Button onClick={logout}>Logout</Button> </> ) : ( <> <Button component={Link} to="/login">Login</Button> <Button component={Link} to="/register">Register</Button> </> )} </Group> ); };然后将 Navigation 组件添加到 Layout 组件中。
这个三天的计划涵盖了前端基础结构的主要部分,包括项目设置、路由、状态管理、API 集成以及基本的 Todo CRUD 操作。接下来,我们可以继续完善用户界面,添加更多功能,并进行进一步的优化。