React 基础知识参考字典

这本字典怎么用

按用途分五组:JSX 与组件、内置组件、Hooks 速查、事件与表单、常见报错速查。每条四件事:签名、一句话语义(写”什么时候用、和谁的区别”)、最小示例、常见坑。字典是查的不是读的——先搜文末速查表定位,再跳回条目。概念的”为什么”在《React 语法要点》,上手过程见本系列的《环境搭建》与《第一个应用》两篇。条目默认运行在函数组件里。

一、JSX 与组件

组内共性:JSX 是 JavaScript 的语法糖,花括号里放的是表达式;能放进 {} 的东西与 .js 文件里能写的东西完全一样。

{ } 表达式插值

往 JSX 里嵌入任意表达式(会求值成一段内容的代码),不是模板变量。

<p>共 {items.length} 条,未完成 {items.filter(i => !i.done).length} 条</p>
<img src={user.avatar} alt={user.name} />   {/* 属性值同样是表达式 */}

坑:只能放表达式不能放语句(if/for 要换成三元与 map);渲染对象会直接报错——”Objects are not valid as a React child”,只能渲染字符串、数字等标量或元素。

条件渲染(&& / 三元 / 提前 return)

三选一:短路与渲染”可有可无”的东西,三元二选一,分支复杂时在组件体内提前 return。

{err && <p className="error">{err}</p>}
{loading ? <Spinner /> : <List />}
function Page({ user }) {
  if (!user) return <Login />      // 早退分支
  return <Dashboard user={user} />
}

坑:{count && …} 在 count 为 0 时渲染出字符串 “0”——布尔与 null 不渲染,数字会。防死写法 {count > 0 && …}。

列表渲染与 key

map 把数组变成元素数组;key 是每项的身份标识,React 靠它对账”哪个节点还是原来那个”。

{todos.map(t => (
  <TodoItem key={t.id} todo={t} />   // key 用稳定业务 id
))}

坑:数组下标当 key,头部插入或删除后节点与数据错位,输入框、勾选状态会串到别的行;随机数 key 每次渲染都变,等于没有。没有 id 就造稳定 id(crypto.randomUUID())。

className 与 style

class 属性写 className;style 收对象不收字符串,数字自动补 px。

<p className="title">标题</p>
<p style={{ color: 'crimson', marginTop: 8 }}>内联样式</p>

坑:动态多个 class 用模板串或库(className={`btn ${active ? 'on' : ''}`}),别写成 class=——那是 HTML,JSX 里告警且部分场景行为不一致。

props 与默认值

组件的输入契约;父传什么子拿什么,子组件只读,改数据只能回调。

function Badge({ tone = 'gray', children }) {   // 解构参数位给默认值
  return <span className={`badge badge-${tone}`}>{children}</span>
}

坑:给 props 对象的嵌套字段赋值(props.item.done = true)看似生效,父组件下一次渲染就覆盖回去;传布尔简写 <Badge dark /> 等价 dark={true},但 dark="false" 是真值字符串——布尔属性别传字符串。

children

标签之间内容的容器,组件组装的原生通道,对应 Vue 的插槽。

function Card({ title, children }) {
  return <section><header>{title}</header>{children}</section>
}
<Card title="标题"><p>内容由调用方决定</p></Card>

坑:children 是普通 prop,可以条件渲染、可以传任何东西(包括函数,渲染属性模式);但别在子组件里修改 children 里的元素——内容的主权在调用方。

二、内置组件

组内共性:React 顶层的特殊组件与 API,不带状态、只改变渲染行为或提供边界信息。

(…

不产生真实 DOM 的包裹器,满足 JSX 单根要求又不留多余节点。

return (
  <>
    <dt>{term}</dt>
    <dd>{desc}</dd>
  </>     // 渲染结果没有多余的 wrapper,dl 结构合法
)

坑:需要传 key 时不能用短语法,必须写全 <Fragment key={id}>——短语法 <> 不接受任何属性。

开发模式下的检查器:故意双调用渲染与 Effect,把不纯的渲染、缺清理的副作用提前暴露。生产构建零影响。

<StrictMode>
  <App />
</StrictMode>
// 挂在入口 createRoot 处即可,Vite 模板默认已带

坑:开发时”Effect 执行了两次”不是 bug,是 StrictMode 在帮你测清理函数;修法不是删 StrictMode,而是把清理写对(见 useEffect 条目)。

声明”这棵子树还没准备好”时的占位边界,配合 lazy 或异步数据使用。

<Suspense fallback={<Spinner />}>
  <LazyDashboard />
</Suspense>

坑:fallback 只在”从无到有”与挂起时显示,已显示的内容更新时不会闪回占位;嵌套多个 Suspense 时占位粒度取最近的那个边界。

React.lazy

把组件的 import 变成”用到时才加载”,产出要放进 Suspense 里的组件。

const Settings = React.lazy(() => import('./Settings.jsx'))
// 路由级代码分割的标准姿势:每个页面组件一个 lazy
<Suspense fallback={<p>加载中…</p>}><Settings /></Suspense>

坑:lazy 接收”返回 Promise 的动态 import”,别写成 React.lazy(import('./x'))(立刻执行、签名不符);组件内部小段代码分割用动态 import + then 即可,不必上 lazy。

三、Hooks 速查

组内共性:Hook 让函数组件接入渲染周期;两条铁律——只在顶层调用、只在组件或自定义 Hook 里调用。执行模型(快照、闭包、依赖数组机制)的完整讲解在《React Hooks 心智模型》,这里只给速查形态。

useState

声明会触发重渲染的状态,返回 [当前值, 设置器]。

const [count, setCount] = useState(0)
setCount(count + 1)        // 基于本次渲染快照的新值
setCount(v => v + 1)       // 函数式更新:拿到队列里的最新值,连用不出错
const [list, setList] = useState(() => loadExpensive())  // 惰性初始化只跑一次

坑:同一事件里连续 setCount(count + 1) 三次只加 1——count 是快照;改对象/数组必须创建新引用(展开、map、filter),原地改界面不动。

useEffect

声明副作用:”依赖数组里的值变化后(含首次),执行这段代码”。

useEffect(() => {
  const id = setInterval(tick, 1000)
  return () => clearInterval(id)   // 清理函数:下次执行前与卸载时都调用
}, [delay])

坑:漏写依赖是最常见 bug 源——闭包拿到的是旧渲染的值,lint 的 exhaustive-deps 警告当 error 对待;不写依赖数组等于每次渲染都执行,里面再 setState 就是死循环。

useRef

不触发重渲染的可变容器,.current 读写;也用于持有 DOM 引用。

const inputRef = useRef(null)
<input ref={inputRef} />
useEffect(() => inputRef.current?.focus(), [])   // 挂载后聚焦

坑:改 ref.current 不触发渲染——要上界面的值用 state;初始值只在首次生效;渲染期间别读写 ref(保持渲染纯度)。

useMemo

缓存昂贵计算的结果:依赖不变就返回上次的值。

const stats = useMemo(
  () => heavyCompute(rows),     // rows 是几千行时才值得缓存
  [rows]
)

坑:先测出慢再加(DevTools Profiler),缓存本身有比较开销;它解决”算得贵”,不解决”引用每次都变”——那是 useCallback 的事。React Compiler(当前为 RC 阶段)已可在新项目试用自动 memoization,新项目可考虑让编译器做。

useCallback

缓存函数引用:依赖不变时返回同一个函数,让子组件的 memo 或 Effect 的依赖比较能通过。

const onSave = useCallback(() => save(row), [row])
<MemoRow row={row} onSave={onSave} />   // 引用稳定,MemoRow 的 memo 才生效

坑:只传给”没被 memo 的子组件”或普通 DOM 时毫无收益,纯增加代码噪音;两层滥用(到处 memo + 到处 useCallback)是可读性反模式,何时值得做见渲染深潜文。

useContext

读取最近 Provider 提供的 context 值,跳过逐层传 props。

const ThemeContext = createContext('light')      // 创建+默认值
<ThemeContext.Provider value={theme}><App /></ThemeContext.Provider>
function Button() {
  const theme = useContext(ThemeContext)          // 任意深度的后代都能读
}

坑:Provider 的 value 变化会让所有消费者重渲染,value 用对象字面量(每次新引用)等于全量广播——用 useMemo 稳住 value,或按更新频率拆成多个 context;只放主题、文案、当前用户这类真全局语义。

四、事件与表单

组内共性:事件名驼峰(onClick 不是 onclick),处理函数收到合成事件(SyntheticEvent)——跨浏览器统一包装的事件对象。

onClick / onChange 等基础事件

把事件处理函数作为 prop 传给元素。

<button onClick={() => setOpen(!open)}>切换</button>
<input onChange={e => setText(e.target.value)} />

坑:onClick={handle()} 立刻执行并把返回值当处理器——要传函数本身 onClick={handle} 或 onClick={() => handle(id)};合成事件是原生事件的轻量包装,React 17 起已移除事件池,异步回调里直接用 e.target.value 是安全的——旧教程里的 e.persist() 不再需要。

onSubmit 与表单提交

表单提交拦在 form 上,回车与提交按钮天然一致。

<form onSubmit={e => {
  e.preventDefault()          // 不拦会整页刷新,state 全丢
  addTodo(text)
}}>
  <input … /><button>添加</button>
</form>

坑:把提交绑在按钮 onClick 上——输入框里按回车不触发;移动端浏览器对 form 的”下一个/完成”也走 submit 路径,绑 form 才都接得住。

受控三件套(input / textarea / select)

表单值收编进 state:value 由 state 出,onChange 写回 state。

<input value={text} onChange={e => setText(e.target.value)} />
<textarea value={memo} onChange={e => setMemo(e.target.value)} />
<select value={lang} onChange={e => setLang(e.target.value)}>
  <option value="zh">中文</option>
</select>

坑:checkbox 与 radio 用 checked 而不是 value:<input type="checkbox" checked={ok} onChange={e => setOk(e.target.checked)} />;只给 value 不给 onChange,输入框锁死打不了字。

文件输入(非受控)

文件路径浏览器不许脚本设置,无法受控,用 ref 直取。

const fileRef = useRef(null)
<input type="file" ref={fileRef} onChange={() => {
  const f = fileRef.current?.files?.[0]   // File 对象在 DOM 上
  if (f) setUploading(f)
}} />

坑:给 file input 设 value 属性无效(只读);同名文件连续选择两次不触发 onChange 时,处理完后手动清 e.target.value = ''。

五、常见报错速查

组内共性:报错文本可直接搜索定位。八成源于三类反模式——状态改法不对、Hook 用法违反规则、Effect 依赖不完整。

症状 真实原因 修法
Warning: Each child in a list should have a unique key map 渲染没给 key,或 key 不稳定(下标、随机数) key 用稳定业务 id;数据没 id 就生成并随数据持久化
Warning: useEffect has a missing dependency Effect 里用了组件内的值但没列进依赖数组,闭包是旧值 把值补进依赖;依赖变化太频繁就调整 Effect 粒度或把逻辑移进事件处理
Too many re-renders. React limits the number of renders… 渲染过程里直接调 setState(如函数体顶层)形成无限循环 setState 移进事件处理或 Effect;初始化用惰性初始化而非”判断后 set”
Warning: Cannot update a component while rendering a different component 渲染组件 A 时顺手改了组件 B 的 state 改数据的动作移进事件处理;确需联动用 Effect 或状态提升
Rendered more hooks than during the previous render Hook 调用进了条件/循环/提前 return,两次渲染数量不一致 Hook 全部放到函数顶层;条件逻辑放进 Hook 内部
Objects are not valid as a React child 花括号里渲染了对象或数组本身 渲染具体字段(obj.name)或先 map 成元素;数组渲染记得 key
开发模式 Effect 执行了两次 StrictMode 故意双调用以暴露缺失的清理 写对清理函数(return 清理逻辑),不要删 StrictMode

速查表

条目 一句话用途 有什么坑
{ } 插值 往 JSX 嵌表达式 放不了语句;渲染对象报错
条件渲染 && / 三元 / 提前 return && 左侧为 0 时渲染 “0”
列表与 key map 出元素数组 下标/随机数当 key 会串位
className / style 类名与内联样式 style 收对象;class= 是 HTML 写法
props 组件输入契约,只读 改嵌套字段会被下次渲染覆盖
children 内容分发通道 内容主权在调用方,别改它
Fragment 无节点的单根包裹 短语法不能带 key
StrictMode 开发期双调用检查器 双执行是特性不是 bug
Suspense 未就绪子树的占位边界 只管”从无到有”的挂起
React.lazy 按需加载组件 参数是返回动态 import 的函数
useState 触发重渲染的状态 快照语义;必须新引用替换
useEffect 依赖变化后执行副作用 漏依赖=旧值;无依赖数组=每次跑
useRef 不触发渲染的可变容器 改 .current 界面不动
useMemo 缓存昂贵计算 先测再加;解决”算得贵”
useCallback 缓存函数引用 不配 memo 用基本没收益
useContext 跨层级读共享值 value 不稳定=全量重渲染
基础事件 onClick/onChange 驼峰绑定 onClick={fn()} 是立刻执行
onSubmit 拦表单提交 不 preventDefault 整页刷新
受控三件套 表单值收编进 state checkbox 用 checked;缺 onChange 锁死
文件输入 ref 直取 File 对象 无法受控;value 只读

边界与延伸

本字典只收基础层:useReducer、useId、useOptimistic、Actions 等进阶 API 与服务端组件语境不在收录范围,以官方 API 索引为准。执行模型的深潜——快照、闭包陷阱、依赖数组机制——在《React Hooks 心智模型》;重渲染时机与 memo/Profiler 实战在《React 渲染与重渲染》;全部概念的系统讲解见开头链接的《React 语法要点》。

版本核实(撰写时检索,2025-07):React 当前稳定版为 19.1.x;本字典收录的组件与 Hooks 均为稳定 API;React Compiler 处于 RC 阶段(2025-04 发布候选版),可自动完成大部分手动 memoization,条目内已注明其对 useMemo/useCallback 的影响。具体以官方文档为准。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇