一、开发前的准备工作:打好地基才能盖高楼
(一)搭建丝滑的 CSS 环境:Stylus 预编译初体验
- 为什么选 Stylus?
Stylus 作为 CSS 的超集,用简洁语法实现变量、混合、函数等高级特性,写起来像 “CSS 开了倍速”~搭配 Vue 社区的 Vite 构建工具,无需复杂配置,安装pnpm add -D stylus后就能直接编译,懒人福音! - 全局样式优化:细节决定体验
设置字体时优先使用-apple-system适配苹果设备, fallback 到 Arial 和无衬线字体,让文字显示更 “原生”。移动端采用rem和vw/vh相对单位,告别死板的px,让布局随屏幕大小自由 “呼吸”。
(二)组件设计:把复杂功能拆成 “乐高积木”
- 按功能划分组件粒度
将 Todo 应用拆分为三大核心组件:负责输入的TodoForm、展示列表的TodoList、单个列表项TodoItem。这种 “功能单一化” 设计就像把复杂任务拆成小目标,维护起来超轻松,还能提升组件复用性和渲染性能哦~
二、React 核心概念扫盲:理解原理才能写好代码
(一)组件通信:父子组件如何 “对话”
-
Props 传递:父传子的 “快递通道”
通过props传递状态(如待办事项列表todos)和自定义事件(如onAddTodo添加回调),子组件通过结构赋值快速获取所需数据:const { todos, onAddTodo } = props; // 解构赋值,简洁又高效
(二)数据绑定:让界面跟着数据 “动起来”
-
React 的单向绑定哲学
区别于 Vue 的v-model双向绑定,React 通过{}将数据绑定到 JSX,用onChange事件实时更新状态:<input value={text} onChange={(e) => setText(e.target.value)} />虽然多写几行代码,但数据流更清晰,避免 “双向绑定黑洞” 导致的调试噩梦~
(三)本地存储:让数据 “持久化”
-
localStorage 使用指南
利用 HTML5 的localStorage存储待办事项,通过setItem/getItem/removeItem操作数据,搭配JSON.stringify和JSON.parse实现对象的序列化与反序列化。对比cookie,它容量更大(5MB vs 4KB)、不参与 HTTP 请求,更适合存储非敏感数据。
| 特性 | localStorage | cookie |
|---|---|---|
| 存储容量 | 5MB | 4KB |
| HTTP 携带 | 不携带 | 自动携带 |
| 过期时间 | 永久有效 | 可设置过期时间 |
| 操作权限 | 仅前端 | 前后端均可 |
三、自定义 Hook 实战:封装逻辑让代码 “轻装上阵”
(一)什么是自定义 Hook?不止是函数封装!
- 核心价值:复用状态与副作用逻辑
自定义 Hook 是一个以use开头的函数,内部可调用useState/useEffect等内置 Hook,将组件逻辑(如状态管理、副作用处理)封装成可复用单元。与普通函数最大的区别是:它能管理响应式状态,让多个组件共享逻辑却互不干扰~
(二)打造专属 useTodos Hook:集中管理待办逻辑
import { useState, useEffect } from 'react';
export const useTodos = () => {
// 初始化状态:从localStorage获取数据,默认空数组
const [todos, setTodos] = useState(() => {
const data = localStorage.getItem('todos');
return data ? JSON.parse(data) : [];
});
// 副作用:数据变化时同步更新localStorage
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]); // 仅在todos变化时执行
// 添加待办事项
const addTodo = (text) => {
setTodos([
...todos, // 保留原有数据
{ id: Date.now(), text, isComplete: false } // 新增待办项
]);
};
// 切换完成状态
const onToggle = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, isComplete: !todo.isComplete } : todo
));
};
// 删除待办事项
const onDelete = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return { todos, addTodo, onToggle, onDelete }; // 暴露所需方法和状态
};
(三)组件中使用 Hook:让逻辑更纯粹
在Todos组件中引入useTodos,一键获取所有待办相关的状态和方法,专注于 UI 渲染:
import { useTodos } from '@/hooks/useTodos';
import TodoForm from './TodoForm';
import TodoList from './TodoList';
const Todos = () => {
const { todos, addTodo, onToggle, onDelete } = useTodos();
return (
<div className="app">
<TodoForm onAddTodo={addTodo} /> {/* 传递添加回调 */}
<TodoList todos={todos} onToggle={onToggle} onDelete={onDelete} /> {/* 传递列表操作方法 */}
</div>
);
};
四、进阶优化:让应用更专业、更高效
(一)路径别名:告别 “../../” 地狱
在vite.config.js中配置alias,用@代替src路径,从此导入组件不再 “山路十八弯”:
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'), // 配置@指向src目录
},
},
});
(二)跨组件通信优化:用 useContext 解决 “层级太深”
当组件嵌套过深(如TodoItem需要访问顶层状态),可结合useContext创建全局上下文,避免层层传递props,让状态访问更直接~
(三)性能细节:这些地方别忽略
- 列表项添加唯一
key:在TodoList中为每个TodoItem设置key={todo.id},帮助 React 精准识别组件,减少不必要的重渲染。 - 输入框即时清空:提交表单后立即调用
setText(''),保持界面与数据状态一致,提升用户体验。
五、Vue vs React:不同场景怎么选?
- 入门难度:Vue 的
v-model双向绑定更简单,适合快速上手;React 的单向绑定和 Hook 机制需要理解函数式编程思维,入门稍难但上限更高。 - 生态差异:Vue 有官方全家桶(Vue Router、Vuex),适合中小型项目;React 生态更开放,搭配 Redux、React Router 等库,适合大型复杂应用。
- 组件风格:Vue 用模板语法,接近 HTML;React 用 JSX,在 JavaScript 中直接写标签,逻辑与视图更紧密。
六、总结:自定义 Hook 让 React 开发更丝滑
通过自定义 Hook,我们将复杂的状态管理和副作用逻辑从组件中抽离,让组件专注于 “做自己”—— 只负责渲染 UI。这种 “逻辑复用 + 关注点分离” 的模式,不仅提升了代码的可维护性,还让团队协作更高效~下次遇到重复的状态管理逻辑,记得用use开头写个 Hook 哦!
现在,试着用本文的思路重构你的 React 项目,让代码像丝滑的巧克力一样,既有层次又美味