上次是文字型的,这次我们来写点代码试试,看看效果怎么样
首先肯定是比较简单的尝试开始
写一个todo应用,主要是看能不能零改动就跑起来
用最简单的提示词
然后就给出了代码
下面给你一个 最小可运行 的 Todo 应用示例,基于 React + Vite(如果你习惯 create-react-app
,思路几乎完全一样,只是文件夹结构略有差异)。
应用包含:
组件 | 作用 |
---|
TodoInput | 新增条目输入框 |
TodoItem | 单个待办项(支持完成/取消、删除) |
TodoList | 渲染 Todo 列表 |
TodoApp /App | 主容器,维护全局 todos 状态 |
安装依赖1 2 3 4
| npm create vite@latest todo-app --template react cd todo-app npm i npm run dev
|
下面按文件展示完整代码(把对应文件替换或新建即可)。
1️⃣ src/main.jsx
1 2 3 4 5 6
| import React from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; import "./index.css";
createRoot(document.getElementById("root")).render(<App />);
|
2️⃣ src/App.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import React, { useState, useEffect } from "react"; import TodoInput from "./components/TodoInput"; import TodoList from "./components/TodoList"; import "./App.css";
function App() { const [todos, setTodos] = useState([]);
useEffect(() => { const stored = localStorage.getItem("todos"); if (stored) { setTodos(JSON.parse(stored)); } }, []);
useEffect(() => { localStorage.setItem("todos", JSON.stringify(todos)); }, [todos]);
const addTodo = (title) => { const newTodo = { id: Date.now(), title, completed: false, }; setTodos([newTodo, ...todos]); };
const toggleComplete = (id) => { setTodos((prev) => prev.map((t) => t.id === id ? { ...t, completed: !t.completed } : t ) ); };
const deleteTodo = (id) => { setTodos((prev) => prev.filter((t) => t.id !== id)); };
return ( <div className="app-container"> <h1>Todo List</h1> <TodoInput addTodo={addTodo} /> <TodoList todos={todos} toggleComplete={toggleComplete} deleteTodo={deleteTodo} /> </div> ); }
export default App;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import React, { useState } from "react"; import "./TodoInput.css";
const TodoInput = ({ addTodo }) => { const [value, setValue] = useState("");
const handleSubmit = (e) => { e.preventDefault(); const trimmed = value.trim(); if (trimmed) { addTodo(trimmed); setValue(""); } };
return ( <form className="todo-input" onSubmit={handleSubmit}> <input type="text" placeholder="Add a new todo..." value={value} onChange={(e) => setValue(e.target.value)} /> <button type="submit">Add</button> </form> ); };
export default TodoInput;
|
4️⃣ src/components/TodoItem.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import React from "react"; import "./TodoItem.css";
const TodoItem = ({ todo, toggleComplete, deleteTodo }) => { return ( <div className="todo-item"> <label> <input type="checkbox" checked={todo.completed} onChange={() => toggleComplete(todo.id)} /> <span className={todo.completed ? "completed" : ""}> {todo.title} </span> </label> <button className="delete-btn" onClick={() => deleteTodo(todo.id)}> × </button> </div> ); };
export default TodoItem;
|
5️⃣ src/components/TodoList.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import React from "react"; import TodoItem from "./TodoItem"; import "./TodoList.css";
const TodoList = ({ todos, toggleComplete, deleteTodo }) => { if (todos.length === 0) { return <p className="empty-msg">No todos yet. Add something!</p>; }
return ( <div className="todo-list"> {todos.map((todo) => ( <TodoItem key={todo.id} todo={todo} toggleComplete={toggleComplete} deleteTodo={deleteTodo} /> ))} </div> ); };
export default TodoList;
|
6️⃣ src/index.css
(可选,简单全局样式)
1 2 3 4 5 6 7 8 9 10 11 12
| html, body, #root { height: 100%; margin: 0; font-family: system-ui, sans-serif; } body { display: flex; justify-content: center; align-items: flex-start; background: #f5f5f5; }
|
7️⃣ src/App.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .app-container { width: 90%; max-width: 480px; background: #fff; padding: 20px; margin-top: 40px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border-radius: 8px; }
.app-container h1 { text-align: center; margin-bottom: 20px; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| .todo-input { display: flex; margin-bottom: 20px; }
.todo-input input { flex: 1; padding: 8px 12px; font-size: 16px; }
.todo-input button { padding: 8px 12px; margin-left: 8px; font-size: 16px; background: #4caf50; color: #fff; border: none; cursor: pointer; }
.todo-input button:hover { background: #45a049; }
|
9️⃣ src/components/TodoList.css
1 2 3 4 5 6 7 8 9 10
| .todo-list { display: flex; flex-direction: column; gap: 8px; }
.empty-msg { text-align: center; color: #777; }
|
🔟 src/components/TodoItem.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| .todo-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; background: #fafafa; border-radius: 4px; }
.todo-item label { flex: 1; display: flex; align-items: center; }
.todo-item input[type="checkbox"] { margin-right: 12px; }
.todo-item .completed { text-decoration: line-through; color: #777; }
.delete-btn { background: transparent; border: none; color: #ff4444; font-size: 20px; cursor: pointer; }
.delete-btn:hover { color: #ff0000; }
|
🎉 运行、打包
1 2 3 4 5
| npm run dev
npm run build
|
🚀 小贴士
- 本地存储:示例中使用
localStorage
让 Todo 在刷新后保留。生产环境可以接
入后端或使用 IndexedDB
之类的更强大存储方案。 - 状态管理:若项目日后变大,可考虑引入
Redux
/zustand
/@tanstack/react-store
等。 - 类型安全:使用
TypeScript
可以防止类型错误;把文件后缀改成 .tsx
并在
package.json
dependencies
增加 typescript
与 @types/react
。 - 单位测试:
jest
、react-testing-library
能帮你保障组件逻辑正确。 - 样式优化:考虑使用
styled-components
/emotion
/tailwindcss
等,让样
式变得更易维护。
现在你就拥有一个完整、可直接跑起的 Todo React 应用,随时可以继续扩展功能(如过
滤、拖拽排序、用户登录等)。祝编码愉快 🚀!
在本地先建个应用1
| npm create vite@latest todo-app --template react
|
这里要注意下,要用vite的话要node版本在20.19+
或者22.12+
还有是需要选择js版本,而不是ts
运行下
这里比较慢的话可以上镜像1
| npm config set registry https://registry.npmmirror.com
|
接着把生成的代码都保存成文件1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ├── src │ ├── App.css │ ├── App.jsx │ ├── assets │ │ └── react.svg │ ├── components │ │ ├── TodoInput.css │ │ ├── TodoInput.jsx │ │ ├── TodoItem.css │ │ ├── TodoItem.jsx │ │ ├── TodoList.css │ │ └── TodoList.jsx │ ├── index.css │ └── main.jsx
|
运行命令
看到效果
![]()
结果是真的直接可用的,为什么要测这个呢,主要原因是一个模型本地可用的探讨,我认为如果是要本地可用,至少在这些相对简单的任务上能够完成得比较好,前面那个只是个提问,并没有什么可以验证正确性的,内容还是比较多的,对于做开发的来说能辅助编程还是比较重要的,并且能够完成一些相对独立完整的任务才是比较可用的初级门槛,只是对内存压力还是比较大的