外贸网站源码多语言泊头公司做网站
2026/1/9 22:33:36 网站建设 项目流程
外贸网站源码多语言,泊头公司做网站,wordpress产品介绍,wordpress给图片添加alt属性在前端开发的学习路径中#xff0c;Todo List#xff08;待办事项清单#xff09;被称为“Hello World”级别的实战项目。虽然看起来简单#xff0c;但它涵盖了 CRUD#xff08;增删改查#xff09;、组件拆分、状态管理等核心逻辑。 今天我们将通过一份基于 Vite React…在前端开发的学习路径中Todo List待办事项清单被称为“Hello World”级别的实战项目。虽然看起来简单但它涵盖了 CRUD增删改查、组件拆分、状态管理等核心逻辑。今天我们将通过一份基于 Vite React Stylus 的源码深入拆解 React 的核心开发模式。1. 项目架构与组件化思维React 的核心思想是组件化。我们将 UI 拆分成独立的、可复用的部分。在这个项目中我们的组件结构非常清晰App(父组件): 整个应用的容器负责“持有数据”和“管理逻辑”。它是唯一的数据源Source of Truth。TodoInput(子组件): 负责用户输入将新任务传递给父组件。TodoList(子组件): 负责展示任务列表处理完成/删除操作。TodoStarts(子组件): 负责展示统计信息总数、剩余、已完成并提供清除功能。这种结构体现了 React 开发的一个重要原则状态提升Lifting State Up。因为TodoList需要展示数据TodoStarts需要统计数据所以我们将数据统一放在它们的共同父组件App中管理。2. 核心知识点拆解2.1 State 管理与 Hooks 高级用法在App.jsx中我们使用了useState来管理任务列表数据。// App.jsx const [todos, setTodos] useState(() { // 知识点Lazy Initialization (惰性初始化) const saved localStorage.getItem(todos); return saved ? JSON.parse(saved) : []; });解析通常我们写 useState([])但这里传入了一个函数。为什么localStorage.getItem是同步操作如果直接写在组件体内每次组件重新渲染都会执行影响性能。惰性初始化传入函数后React 只会在组件首次渲染时执行该逻辑后续渲染会跳过这是性能优化的一个小技巧。2.2 受控组件 (Controlled Components)在TodoInput.jsx中我们处理用户输入的方式与 Vue 的v-model不同。// TodoInput.jsx const [inputValue, setInputValue] useState(); // ... render input typetext value{inputValue} // 1. 绑定状态 onChange{e setInputValue(e.target.value)} // 2. 监听变化并更新状态 /解析React 提倡单向数据流。输入框的值由 React state (inputValue) 控制。用户的输入触发onChange。setInputValue 更新 stateReact 重新渲染组件输入框显示新值。这被称为受控组件它保证了数据和视图的严格同步。2.3 组件通信父传子 (Props)数据如何从App流向TodoList通过Props。// App.jsx (父组件) TodoList todos{todos} ... / // TodoList.jsx (子组件) const TodoList (props) { const { todos } props; // 解构获取数据 // ... }解析父组件将 todos 数组作为属性传递给子组件子组件只能读取严禁直接修改 Props。这是 React 数据流向单一性的铁律。2.4 组件通信子传父 (回调函数)子组件想要修改数据怎么办例如用户在 TodoInput 点击了添加或者在 TodoList 点击了删除。答案父组件传递“修改数据的方法”给子组件。场景一添加任务// App.jsx (父组件定义方法) const addTodo (text) { setTodos([...todos, { id: Date.now(), text, completed: false }]) } // 传递给子组件 TodoInput onAdd{addTodo} / // TodoInput.jsx (子组件调用) const handleSubmit (e) { e.preventDefault(); onAdd(inputValue); // 调用父组件传下来的函数 setInputValue(); }场景二兄弟组件通信间接TodoInput 添加的数据最终显示在了 TodoList 中。它们之间没有直接联系而是通过TodoInput通知App更新 state。Appstate 变化触发重新渲染。App将新的todos传给TodoList。这就是状态共享的魅力。2.5 交互逻辑详解不可变数据的删除与更新在 React 中更新状态State有一个核心原则永远不要直接修改 State而是用新数据替换旧数据。这一点在删除和勾选操作中体现得淋漓尽致。1. 删除功能Filter 的妙用点击删除按钮时我们需要移除列表中的某一项。在App.jsx中我们没有使用数组的splice方法因为它会直接修改原数组而是使用了filter。// App.jsx const deleteTodo (id) { // 知识点Immutable Update (不可变更新) // filter 返回一个新数组不包含被删除的那一项 setTodos(todos.filter(todo todo.id ! id)) }在 UI 组件TodoList.jsx中我们需要注意事件绑定的写法// TodoList.jsx button onClick{() onDelete(todo.id)}Delete/button⚠️ 新手易错点一定要写成箭头函数 () onDelete(todo.id)。如果写成 onClick{onDelete(todo.id)}函数会在组件渲染时立即执行导致无限循环报错。2. 勾选切换Map 与展开运算符这是 React 数组更新中最常见的模式。当用户点击 Checkbox 时我们需要把数组中特定 ID的那一项的completed状态取反同时保持其他项不变。// App.jsx const toggleTodo (id) { setTodos(todos.map(todo // 遍历每一个 item找到 id 匹配的那一个 todo.id id ? { ...todo, // 知识点Spread Operator (展开运算符) 复制原有属性 completed: !todo.completed // 覆盖 completed 属性 } : todo // id 不匹配的项保持原样 )) }逻辑解析todos.map生成一个全新的数组保证不修改原todos引用。...todo利用 ES6 的展开运算符将旧对象的所有属性id, text复制到新对象中。completed: !todo.completed单独覆盖我们需要修改的属性。在TodoList.jsx中我们将这个逻辑绑定到 input 的onChange事件上同时利用checked属性实现受控组件的双向绑定效果// TodoList.jsx input typecheckbox checked{todo.completed} // 视图状态依赖数据 onChange{() onToggle(todo.id)} // 数据更新依赖交互 /同时也利用这个状态来动态控制 CSS 类名实现完成时的划线样式li key{todo.id} className{todo.completed ? completed : }2.6 列表渲染与 Key在TodoList.jsx中我们使用map方法渲染列表// TodoList.jsx todos.map(todo ( li key{todo.id} className{todo.completed ? completed : } {/* ...内容 */} /li ))解析Key 的重要性React 需要key来识别哪些元素改变了、添加了或删除了。这里我们使用了todo.id(时间戳) 作为唯一标识。切记不要使用数组索引(index)作为 key这在列表顺序变化时会导致严重的渲染错误或性能问题。条件渲染我们使用三元运算符todos.length 0 ? (...) : (...)来处理空状态的展示。2.7 副作用处理 (useEffect)如何实现数据持久化刷新页面数据不丢失我们使用了useEffect。// App.jsx useEffect(() { localStorage.setItem(todos, JSON.stringify(todos)); }, [todos])解析useEffect用于处理副作用Side Effects比如数据获取、订阅、手动修改 DOM 等。依赖数组[todos]这意味着每当todos状态发生变化时React 就会执行这个函数将最新的数据同步到 LocalStorage。2.8 逻辑复用与短路运算在TodoStarts.jsx中有一个很优雅的条件渲染写法// TodoStarts.jsx { completed 0 ( button onClick{onClearCompleted}Clear Completed/button ) }解析利用 JavaScript 的逻辑与 () 运算。只有当 completed 0 为真时后面的 Button 才会渲染。这比写 if/else 要简洁得多。3. 总结通过这个小小的 Todo List我们完整实践了 React 开发的“黄金法则”数据驱动视图UI 是 State 的投影 (UI f(State))。单向数据流数据向下流动 (Props)事件向上冒泡 (Callback)。不可变性在App.jsx的deleteTodo等方法中我们使用了filter和map返回新数组而不是直接修改原数组 (push/splice)这对 React 识别状态变化至关重要。// ❌ 错误示范 todos.push(newItem); // ✅ 正确示范 (不可变更新) setTodos([...todos, newItem]);4. 项目源码4.1 App.jsximport{useState,useEffect}fromreactimport./styles/app.stylimportTodoListfrom./components/TodoList.jsximportTodoInputfrom./components/TodoInput.jsximportTodoStartsfrom./components/TodoStarts.jsxfunctionApp(){// 子组件共享的数据状态const[todos,setTodos]useState((){// 高级用法constsavedlocalStorage.getItem(todos);returnsaved?JSON.parse(saved):[];});// 子组件修改数据的方法constaddTodo(text){setTodos([...todos,{id:Date.now(),text,completed:false}])}constdeleteTodo(id){setTodos(todos.filter(todotodo.id!id))}consttoggleTodo(id){setTodos(todos.map(todotodo.idid?{...todo,completed:!todo.completed}:todo))}constclearCompleted(){setTodos(todos.filter(todo!todo.completed))}constactiveCounttodos.filter(todo!todo.completed).length;constcompletedCounttodos.filter(todotodo.completed).length;useEffect((){localStorage.setItem(todos,JSON.stringify(todos));},[todos])return(div classNametodo-apph1My Todo List/h1{/* 自定义事件 */}TodoInput onAdd{addTodo}/TodoList todos{todos}onDelete{deleteTodo}onToggle{toggleTodo}/TodoStarts total{todos.length}active{activeCount}completed{completedCount}onClearCompleted{clearCompleted}//div)}exportdefaultApp;4.2 TodoInput.jsximport{useState}fromreactconstTodoInput(props){console.log(props);const{onAdd}props;// react 不支持 Vue 中的 v-model 那样的双向绑定react 认为这样性能不好// react 只支持单向绑定性能好 onChange 实现数据和视图的同步const[inputValue,setInputValue]useState();consthandleSubmit(e){e.preventDefault();onAdd(inputValue);setInputValue();}return(form classNametodo-inputonSubmit{handleSubmit}input typetextvalue{inputValue}onChange{esetInputValue(e.target.value)}/button typesubmitAdd/button/form)}exportdefaultTodoInput;4.3 TodoList.jsxconstTodoList(props){const{todos,onDelete,onToggle}props;return(ul classNametodo-list{todos.length0?(li classNameemptyNo todos yet!/li):(todos.map(todo(li key{todo.id}className{todo.completed?completed:}labelinput typecheckboxchecked{todo.completed}onChange{()onToggle(todo.id)}/span{todo.text}/span/labelbutton onClick{()onDelete(todo.id)}Delete/button/li)))}/ul)}exportdefaultTodoList;4.4 TodoStarts.jsxconstTodoStarts(props){const{total,active,completed,onClearCompleted}props;return(div classNametodo-startspTotal:{total}|Active:{active}|Completed:{completed}/p{completed0(button onClick{onClearCompleted}classNameclear-btnClear Completed/button)}/div)}exportdefaultTodoStarts;

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询