视频版
🎙 欢迎回到《前端达人 · React播客书单》第 18 期。
今天,我们将对第二阶段的内容进行系统复盘,重点是两个关键词:样式 与 Hooks。
样式,决定组件“长什么样”
Hooks,决定组件“怎么动起来”
我们不但会回顾 CSS Modules、Emotion、Tailwind 的使用场景,还会穿插 useState
、useEffect
、useRef
等核心 Hooks 的使用技巧,并在最后带来一个实战组件:可折叠面板 Accordion,来一次彻底的知识整合。
📦 第一部分:样式方案复习
✅ Plain CSS & CSS Modules
// 传统方式
import './App.css'
// 模块化方案
import styles from './Button.module.css'
<button className={styles.primary}>Submit</button>
CSS Modules 优势:
避免样式全局污染
类名自动哈希化,适合组件封装
Create React App 默认支持
适用场景:中等规模组件项目,团队需要一定风格约束。
✅ Emotion:主流 CSS-in-JS 方案
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const style = css`
background: #f0f0f0;
padding: 16px;
`
优势:
样式与逻辑写在一起,更具组件一致性
允许使用 props 动态控制样式
天然适配 TypeScript 类型系统
适用场景:组件库、设计系统 或 需要逻辑控制样式的复杂交互组件
✅ Tailwind CSS:原子化的实用流派
<button className="bg-indigo-600 text-white px-4 py-2 rounded">
Click me
</button>
优势:
无需命名 class,写一个类就是一个功能
class 命名语义明确、设计一致
配合设计 token、组件库使用,提升协作效率
适用场景:页面开发、追求一致性的中大型前端项目
⚙️ 第二部分:Hooks 系统复盘
✅ useState vs useReducer
const [count, setCount] = useState(0)
适用于简单状态(数字、布尔值、字符串)
const [state, dispatch] = useReducer(reducer, initialState)
适用于复杂状态逻辑,如:
多个字段一起更新
状态变更依赖 action 类型
希望将状态逻辑集中统一管理
📌 记住一句话:状态逻辑复杂,就用 useReducer
✅ useEffect:副作用处理专家
useEffect(() => {
fetchData()
return () => cleanup()
}, [dependency])
掌握 3 种依赖数组写法:
依赖数组 | 执行时机 |
---|---|
[] | 组件首次挂载 |
[var] | var 变化时执行 |
空(不填) | 每次渲染后执行 |
✅ 性能与引用类 Hooks:useRef / useMemo / useCallback
Hook | 场景 |
---|---|
useRef | 缓存 DOM 或值,不触发重渲染 |
useMemo | 缓存计算结果,避免重复运算 |
useCallback | 缓存函数引用,优化子组件渲染 |
const total = useMemo(() => calculate(items), [items])
const handler = useCallback(() => doSomething(), [items])
🧪 第三部分:实战组件构建
🎯 目标:可折叠面板(Accordion)
功能说明:
点击按钮,内容展开或收起
内容高度自动适配,支持过渡动画
无需引入三方库,完全自定义实现
💡 技术实现拆解
功能点 | 技术方案 |
---|---|
状态控制 | useState 管理 isExpanded |
DOM 尺寸测量 | useRef 获取 scrollHeight |
触发动画 | useEffect 控制 style.height |
函数优化 | useCallback 记忆点击事件 |
样式实现 | Tailwind + transition 类名 |
🧱 精简实现代码(参考)
const [isExpanded, setIsExpanded] = useState(false)
const contentRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const el = contentRef.current
if (!el) return
el.style.height = isExpanded ? `${el.scrollHeight}px` : '0px'
}, [isExpanded])
配合样式:
<div className="overflow-hidden transition-all duration-300" ref={contentRef}>
<p className="p-4">这里是内容区域</p>
</div>
📌 学习建议 & 调试技巧
💻 React DevTools:观察状态、props 变化最强工具
🧠 错误提示别忽略,TS 的类型报错=最佳调试助手
📘 文档永远是第一资源:React Hooks 官方文档
✅ 总结与展望
已掌握 | 意义 |
---|---|
样式模块化思路 | 让组件更美观、可维护 |
Hooks 使用模式 | 让组件更具行为逻辑和性能优化能力 |
实战练习能力 | 把知识点真正用于构建功能型组件 |
🔮 下一步内容:进入第三阶段
📌 主题:React 路由与远程数据处理
我们将学习:
react-router-dom
的现代写法动态路由参数与页面懒加载
API 数据请求与缓存逻辑
#React #React播客 #前端播客 #前端达人 #TypeScript