diff --git a/hhs/REACT/1. 基础篇/02-JSX 语法.md b/hhs/REACT/1. 基础篇/02-JSX 语法.md index 7b7dfe9..6e002e5 100644 --- a/hhs/REACT/1. 基础篇/02-JSX 语法.md +++ b/hhs/REACT/1. 基础篇/02-JSX 语法.md @@ -115,13 +115,23 @@ function TodoList({ items }: { items: TodoItem[] }) { ## JSX 事件绑定 +> [!tip] 与 HTML 事件的核心区别 +> - **HTML**: `onclick="handler()"` → 字符串属性,浏览器运行时解析,在全局作用域求值 +> - **JSX**: `onClick={handler}` → 驼峰命名,接收一个 **JS 函数引用**作为 props,不是字符串 +> - JSX 没有"字符串属性"的概念——所有 `{} ` 内都是 JavaScript 表达式 + ```jsx function ClickCounter() { const [count, setCount] = useState(0); - // 驼峰命名,不要写 onClick="handler()" + // ✅ 正确:驼峰命名 onClick,值为函数引用(不加括号) const handleClick = () => setCount(c => c + 1); + // ❌ 错误示范 + // ); } ``` +> [!question] "闭包捕获当前 id"到底什么意思? +> +> **类比**:不用箭头函数就像点餐时一次性把所有订单全交给后厨(渲染时立刻执行);用箭头函数是给每个商品贴一张任务卡——卡片上记着当时的 `id`,等用户点击时才展开执行。 +> +> **代码演示**(以列表渲染为例): +> +> ```tsx +> const todos = [{ id: 1, text: "买菜" }, { id: 2, text: "取快递" }]; +> +> // ❌ onClick={onDelete(todo.id)} — 括号让它变成"调用语句" +> todos.map(todo => ( +> // 第一次循环 → 立刻执行 onDelete(1),item1 被删 ✗ +> // 第二次循环 → 立刻执行 onDelete(2),item2 被删 ✗ +> // 页面还没展示,三个都删光了 +> +> )); +> +> // ✅ onClick={() => onDelete(todo.id)} — 没有括号,只是"存一张任务卡" +> todos.map(todo => ( +> // 每次循环创建新的箭头函数,每个闭包封存了当前的 todo.id +> // #1 的闭包记忆: todo.id = 1 +> // #2 的闭包记忆: todo.id = 2 +> // 用户点击哪个按钮,就取出对应的任务卡执行 +> +> )); +> +> // ✅ 如果不需要参数,直接传引用即可 +> +> // 等价于 → +> // 但前者更简洁(没有额外创建箭头函数的开销) +> ``` +> +> **什么是闭包?** 函数 + 它被创建时所在的词法环境。每次循环创建的箭头函数都是一个独立的闭包,记住了自己出生时的 `id` 值。即使后面 `id` 变了(比如在 for 循环中),闭包里的值也不会跟着变。 + +### 为什么需要包装?核心逻辑 + +| 情况 | 做法 | 原因 | +|------|------|------| +| 不需要传参 | `onClick={handler}` | 直接传函数引用,React 在点击时调用 | +| 需要传外部变量 | `onClick={() => handler(val)}` | 箭头函数作为中间层,传入所需参数 | +| 需要访问原事件对象 | `onClick={(e) => { e.stopPropagation(); handler(id); }}` | 同时处理事件和自定义参数 | +``` + > [!warning] 常见陷阱 -> - ~~`onClick={onDelete(id)}`~~ ❌ — 会在渲染时立即执行 `onDelete`,而非点击时执行 -> - ~~`onClick={onDelete}`~~ — 缺少参数,不知道要删除哪个 -> - ✅ **正确姿势**:`() => onDelete(id)` — 用箭头函数延迟执行并捕获参数 -> - 💡 如果不需要参数,直接传引用即可:`onClick={handleClick}`(不要加括号) +> - ~~`onClick="handler()"`~~ ❌ — 字符串赋值给 onClick prop,React 试图调用字符串时会报错 +> - ~~`onClick={handler()}`~~ ❌ — 渲染时立即执行 handler,onClick = undefined(通常是函数返回值) +> - ~~`onClick={handler}`~~ ❌ — 缺少参数,不知道要操作哪个元素 +> - ✅ **正确姿势**:无参直接传引用 `onClick={handleClick}`;有参用箭头函数延迟执行 `onClick={() => handler(id)}` ### 常用合成事件类型