useState 总在“复读”?一文吃透渲染快照与闭包陷阱
“为什么我的 useState 总是在‘复读’”——如果你也喊出过这句话大概率是遇到了三件套状态更新后不生效、回调里读到的永远是旧值、连续 setState 之后数值却纹丝不动。这三个现象其实同根同源指向 React 一个非常核心但容易被初学者忽略的设计渲染快照。我在接手某个中后台项目时就曾亲眼看过一段代码连续点击一个按钮页面上的计数始终停留在 1直到刷新才长到 2。排除了缓存、排除了接口最后发现是同事在事件回调里连写了三个setCount(count 1)还自信地以为会加三次。这篇文章不打算只把正确答案摆出来而是想带着你把“快照”这件事从原理到排查彻底捋一遍让你以后遇到类似问题能够一眼定位。先给个结论useState 的“复读”不是 bug也不是 React 故意刁难你而是它渲染模型下的必然结果。理解了这个模型你就能把那些“玄学”问题变成“有章可循”的常规判断。1. 问题现场useState 的“复读”现象到底长什么样1.1 最常见的三类怪象我总结了一下工作中遇到“状态复读”基本逃不出这三类。先看第一类事件回调里连续更新。const [count, setCount] useState(0); const handleClick () { setCount(count 1); setCount(count 1); setCount(count 1); }; // 点一次按钮之后count 变成了几 // 答案是 1不是 3。第二类setState 之后立刻读取状态。const handleClick () { setCount(count 1); console.log(count); // 依然是旧的 count比如 0 };第三类状态明明变了但回调里拿到的还是旧值。这种最容易让人抓狂因为界面上数字已经更新可你在 setTimeout 里打印却始终是初始值。const [user, setUser] useState({ name: 匿名 }); useEffect(() { setTimeout(() { console.log(user); // 为什么一直打印初始的 { name: 匿名 } }, 3000); }, []); const handleLogin () { setUser({ name: 管理员 }); };这三个场景看起来各不相同背后的原因却是同一个你所访问的user、count并不是一个“活的变量”而是某一次特定渲染下的“快照”。1.2 从代码现象到核心矛盾你可以把 React 的每一次渲染想象成给整个 UI 拍一张照片。照片里有一份当时的 state、当时的 props、当时的函数定义。当用户触发了某个行为React 开始重新拍一张新照片。新的照片里有新的 state、新的 props、新的函数。旧照片并不会被改写成新照片它只是被丢弃了。问题就出在这里如果你在某个事件回调中 hold 住了旧照片里的函数和状态那这个函数无论之后调用多少次它眼里看到的永远是旧照片里的世界。这就是闭包和快照叠加造成的“复读”现象。矛盾的核心在于你的直觉是“变量会随着赋值而变化”而 React 的设计哲学是“state 是不可变的快照”。这两种思维方式之间的落差就是你会觉得 useState 在“复读”的根本原因。2. 渲染快照机制React 为什么要把状态“拍下来”2.1 什么是渲染快照要理解快照先要改变一个看待 React 组件的视角。别把组件函数当成“模板引擎”它其实是一个“帧生成器”。组件函数每次执行就是根据当前的 state 生成一帧 UI 描述。function Counter() { const [count, setCount] useState(0); // 这整个函数体是当前这一次渲染的快照内容 return ( div p{count}/p button onClick{() setCount(count 1)}1/button /div ); }在这个快照里count是固定的onClick里捕获的count也是固定的。任何一次点击实际上都是“旧快照里的 onClick”被触发。它可以调用 setCount但 setCount 不会去修改当前快照里的count它只会排队等着触发下一次渲染产生一个新快照。所以 React 官方文档反复强调在单次渲染中props、state 和事件处理函数都是不变的。这里的不变不是说你不能修改变量而是说在这一次快照的时间范围内它们就是常量。2.2 批处理与更新队列接下来要理解 setState 之后到底发生了什么。React 收到 setState 调用后并不会立刻同步地更新 state而是把这次更新放进一个队列等当前事件处理完统一 flush 一次产生一个新的渲染。这个机制叫批处理Batching。React 18 之后几乎所有的自动批处理都生效了包括 Promise 回调、setTimeout 里的更新。这意味着你在一个事件里调十次 setState最终可能会只触发一次重新渲染。和渲染快照结合起来就出现了前文的经典问题当你在一次事件里多次setCount(count 1)时每次相加的count都来自同一张旧快照。旧快照里的count是 0所以加了三次也是0 1最终结果是 1而不是 3。如果想让三次累积你需要告诉 React“请基于最新排队结果来更新”也就是函数式更新setCount(prev prev 1); setCount(prev prev 1); setCount(prev prev 1);函数式更新的参数是“队列中的上一个结果”相当于让 React 在内部按照顺序执行一个流水线而不是直接读取当前快照里的常量。这是理解“复读”问题最重要的突破口。2.3 为什么“快照”设计反而是好设计很多初学者会问“搞这么绕为什么不直接给我一个可以随时读写的最新状态”答案是快照模型让 React 的渲染变得可预测也让并发特性成为可能。你可以把 React 想象成一个摄影师。它按下快门前需要先让所有人摆好姿势也就是收集完整的 state、props。如果模特中途换衣服摄影师会不知所措。但当模特保持那个姿势时摄影师拍下的照片是稳定的、一致的。UI 不会出现“上半身是新数据、下半身是旧数据”的撕裂状态。这一点尤其在 React 18 的并发渲染中体现得很明显。React 可以在多个渲染版本之间来回切换仍然保证每个组件看到的 props 和 state 是一致的快照。如果 state 是“活变量”并发渲染就根本无法安全地实现。所以快照不是临时补丁而是整个新架构的地基。3. 逐个击破四种典型“复读”场景的原理与正确写法3.1 场景一setState 后立即读 state为什么还是旧值这个问题我见过太多次尤其是在需要连续操作然后上报数据的业务里。比如表单提交前有人会在 handleSubmit 里先 setState然后马上读取这个 state 去拼接口参数。结果发现读到的永远少一步。先看代码const [form, setForm] useState({ name: }); const handleSubmit () { setForm({ name: 张三 }); console.log(form); // { name: } submit(form); // 提交的是空 name接口炸了 };原因再清晰不过setForm只是把新状态放进了队列当前这次渲染里form还是旧快照中的{ name: }。事件函数还没有结束React 也不会重新执行组件函数。所以你在 setState 之后无论怎么读读到的都是旧值。这里的正确做法是如果提交逻辑需要用到新状态那就不应该依赖 state 变量而是直接用一个局部变量。你怎么知道答案你就怎么写const handleSubmit () { const nextForm { name: 张三 }; setForm(nextForm); submit(nextForm); // 这里用的是局部变量而不是 state };这一条看似废话却是新手最容易踩的坑。我自己的经验是任何时候当你发现自己要在 setState 之后马上读 state停下来问问自己——我需要的到底是“下一次渲染的值”还是“这次事件决策用的值”如果是前者让 UI 自然更新如果是后者请把值保存在局部变量里。3.2 场景二定时器与事件回调里的闭包旧值第二种情况更隐蔽。界面上 count 已经变成 2但一个定时器里打印 count 永远是 0。很多人以为是 React 没更新其实是闭包把旧快照牢牢抓住了。来复现一下const [count, setCount] useState(0); const handleStart () { setInterval(() { console.log(count); // 永远打印 0 }, 1000); };这段代码里setInterval的回调函数是在第一次渲染时创建的它捕获了第一次渲染中的count快照。后续 count 变化定时器的回调依然是那张旧快照里的函数所以它读到的 count 永远是 0。这里有一个非常关键的概念区分变量名是count但每次渲染都有自己的count。闭包访问的是创建它时所在那一次渲染的count而不是“最新的”count。解决思路有两个。第一个思路是绕过快照用 ref 保存可变值const countRef useRef(0); const handleStart () { setInterval(() { console.log(countRef.current); // 读取 ref 的 current始终最新 }, 1000); }; const handleUpdate () { countRef.current 1; setCount(countRef.current); };ref 和 state 最大的区别在于ref 是一个“可变盒子”修改ref.current不会触发重新渲染但所有闭包都能通过同一个 ref 对象访问到最新的current。所以它非常适合在定时器、订阅、事件监听里存放“需要最新值但不参与渲染”的数据。第二个思路是让 effect 重新订阅每次渲染都创建新的定时器逻辑useEffect(() { const timer setInterval(() { console.log(count); }, 1000); return () clearInterval(timer); }, [count]);这个方案的缺点是定时器会被频繁重置性能和语义上不一定理想。在绝大多数“定时器轮询最新状态”的场景里ref 才是更符合直觉的方案。3.3 场景三连续多次 setState 为什么数值不叠加这个问题已经在第一节出现过了。我再把原理和完整解法展开讲。核心其实就是两个词批处理和快照。const handleClick () { setCount(count 1); // 第一次加 setCount(count 1); // 第二次加 setCount(count 1); // 第三次加 };由于三次count 1都在同一张快照上计算count 都是同一个旧值比如 0。React 把三次设置排队后最终取的是最后一次计算的结果也就是 1。这不是“只执行了一次”而是三次执行了但结果相同。马上有人会问“那我分开写在三个不同的事件处理函数里就正常吗”是的。因为那三次 setCount 发生在三次不同渲染的瞬间每次 count 已经从 0 变成 1再变成 2。每个事件拥有不同的快照。要在同一次事件里完成累加函数式更新是唯一的标准答案const handleClick () { setCount(prev prev 1); setCount(prev prev 1); setCount(prev prev 1); };这样写React 会把三个更新函数依次应用到队列上前一个函数的返回值会作为后一个函数的入参。0 - 1 - 2 - 3最终 count 是 3。补充一个经验如果某个状态需要根据自身旧值进行复杂计算并且可能在短时间内多次触发尽量默认使用函数式更新。这能避免你在未来某天为了“临时多调用一次”而冥思苦想。3.4 场景四set 了同一个值组件不重新渲染还有一种“复读”setState 传入了和当前 state 一样的新值React 判断“没有变化”于是直接跳过重新渲染。这个机制来自 React 内部的Object.is比较。const [obj, setObj] useState({ count: 0 }); const handleClick () { obj.count 1; setObj(obj); // 传入同一个对象引用 };这段代码是无效的。虽然obj.count变成了 1但对象的引用没有变React 用Object.is判断新旧对象相同于是不触发重新渲染。这就是典型的“数据变了UI 纹丝不动”。解决办法是创建新引用const handleClick () { setObj({ ...obj, count: obj.count 1 }); };使用扩展运算符或者Object.assign生成一个新对象React 在比较新旧引用时发现不同才会触发渲染。这个坑在数组上更常见很多人arr.push()之后 setArr(arr)数据变了视图不动。记住一句话让 React 识别变化靠的不是值变了而是引用变了。4. 从“复读”到可控问题定位与调试技巧4.1 判断问题是出在快照还是异步当状态表现异常时先别急着改代码先归类。我把定位过程分成三步。第一步看触发时机。如果问题出现在“事件处理期间”比如点击、表单提交中大概率是快照问题闭包效应。如果问题出现在“数据请求回来之后”需要考虑是不是异步函数里捕获了旧快照。第二步看代码里的访问路径。把状态打印出来打印的位置很关键。如果是在组件函数顶层 console.log它能打到每一次渲染的状态如果是在回调或定时器里 console.log它打的是定义该回调时所在渲染的状态。第三步确认有没有使用最新值方案。如果你发现自己为了读取最新值把依赖项写进 useEffect 数组里这其实走的是“重新订阅”路线如果你用 ref 保存走的是“共享可变”路线。两条路线适应不同场景没有绝对谁优谁劣。下面这个表格可以帮你快速定位现象直接原因首选解法setState 后立刻 console.log 是旧值渲染尚未发生用局部变量参与后续逻辑定时器里读取状态始终是初始值闭包捕获了旧渲染快照用 ref 保存最新值连续多次 setState 结果只加一次同一快照下计算批处理取末次使用函数式更新改对象属性后 setObj 不渲染对象引用未变化创建新引用再 set数据更新了但 UI 没变引用比较未通过检查是否直接修改了原对象4.2 调试快照问题的几种实用技巧第一个技巧是故意把组件渲染次数暴露出来。在组件里增加一个模拟计数器每次渲染加一配合状态打印你就能看到“setState 触发了渲染”还是“setState 被忽略了”。function DebugCounter() { const [count, setCount] useState(0); const renderCount useRef(0); renderCount.current 1; return ( div pcount: {count}/p prender times: {renderCount.current}/p button onClick{() setCount(count 1)}1/button button onClick{() setCount(prev prev 1)}函数式1/button /div ); }如果你发现点“1”按钮时 render times 没有增加说明 React 判定新旧状态一致没有重新渲染。这能帮你区分“状态没变”和“状态变了但读取方式不对”。第二个技巧是使用 React DevTools 的高亮更新功能。每次渲染时被更新的组件会高亮闪烁。这个功能对排查“为什么这个组件没更新”很有帮助也比单纯打日志更直观。第三个技巧是在闭包里临时挂载一个window.__latest变量把最新状态暴露到全局。虽然这不是生产代码的正确做法但调试阶段非常高效。useEffect(() { window.__latest count; }, [count]); // 然后在 console 里手动执行 window.__latest 确认最新值这种方法能帮你快速确认闭包里读到的值和全局最新的值是否一致。如果一致问题出在闭包如果不一致问题出在渲染时机。4.3 如何在团队里避免这类“复读”bug快照问题是非常典型的“单人能躲、多人容易回潮”的坑。我在团队代码审查时最常扫到的三个雷区是事件处理里读 state、setTimeout 里读 state、useEffect 里 setState。第一个雷区事件处理里读 state可以约定“事件内需要新值就用新计算出来的局部变量”。第二个雷区定时器或订阅回调里读 state可以约定“非渲染状态一律放 ref”。第三个雷区useEffect 里 setState如果 setState 之后还要基于这个状态做其他操作把操作一并放进 effect 依赖项里不要在 setState 之后继续读。另外如果你在写自定义 Hooks我建议把“返回最新值的 ref”作为一个通用工具暴露出去function useLatest(value) { const ref useRef(value); useEffect(() { ref.current value; }, [value]); return ref; }这个useLatest是我个人最常用的自定义 Hook。任何时候当某个异步回调需要读取最新 state 时直接用useLatest包装一下问题迎刃而解const [count, setCount] useState(0); const latestCount useLatest(count); const handleStart () { setInterval(() { console.log(latestCount.current); // 始终打印最新 count }, 1000); };它既不触发额外渲染也不破坏闭包的稳定结构。如果你的项目里还没有这个 Hook建议现在就加上。5. React 18、19 时代的快照新变化与进阶思考5.1 自动批处理范围扩大了但快照逻辑没变React 18 之前React 只在浏览器原生事件和生命周期函数里进行批处理。在 Promise、setTimeout、原生事件监听器里的 setState会被拆成多次渲染。React 18 开始自动批处理覆盖了所有场景这也让“复读”更容易出现。举个例子在 React 18 之前fetch(/api/data).then(() { setA(a a 1); setB(b b 1); // 这里可能会触发两次渲染也可能一次 });而现在这段代码只会触发一次渲染。批处理让性能更好但也意味着你更不能依赖“setState 之间读取实时值”。如果你的代码是直接从 React 17 升上来的要特别检查那些在 Promise 回调中连续 setState 并读取中间状态的逻辑。React 19 的 Canvas ref 回调函数和 Actions 特性也建立在同一套渲染模型上快照和不可变性依旧是内核。理解好 useState 的这条主线你就能很容易地理解这些新特性。它们不是另起炉灶而是在同一个地基上盖新的屋子。5.2 并发特性下的“过期快照”是特性不是 bugReact 18 引入了并发渲染。你可以用useTransition把一个低优先级的更新标记为“可打断的”。这会导致一个非常有意思的局面屏幕上显示的是 A 版本内部另一个 B 版本正在后台渲染。如果 B 版本被中断你可能会短暂地看到“旧快照”里的数据。很多从旧版本升上来的同学第一次遇到这种“界面和状态短暂不一致”的情况都会慌。其实这不是状态没更新而是渲染优先级决定的暂时现象。这类场景不建议用“setState 后读取”的思路去解决而是应该让 UI 自己反映正在加载的状态。const [isPending, startTransition] useTransition(); const handleSearch (keyword) { startTransition(() { setSearchResult(keyword); }); };在isPending为 true 时展示一个加载提示这样用户就不会因为 UI 短暂停留在旧快照而感到困惑。理解快照之后你会发现这些并发特性反而变得自然了。5.3 被忽略的边界场景受控组件、Reducer 与不可变数据最后想聊聊几个容易被忽视但很常见的边界场景它们本质上都是快照问题的变种。第一个是受控组件。input的value绑定 state如果onChange里没有正确 setState输入框就会表现的像“复读”一样页面上的内容没有跟着你敲打的字符变化。这不是渲染快照的问题但症状很像排查时要注意区分。第二个是useReducer。它的行为模式和 useState 基本一致dispatch 之后不能立刻读取最新 state连续 dispatch 时也需要依赖 reducer 的纯函数特性。如果 reducer 内部直接修改了 state 对象而不是返回新对象也会触发“不渲染”的坑。第三个是不可变数据。我之前用Immer或类似工具处理复杂嵌套对象但踩过的坑是在 saga 回调里定义好一个 draft 对象然后 setState 时传入了同一个引用导致 React 认为没有变化。推荐的做法是所有传给 setState 的新对象都确保是从不可变操作中新生成的。如果项目允许我也会在团队里推行一种约定编写 reducer 和 setState 传参时永远使用不可变更新方式禁止直接修改原对象。这些看起来和快照无关但只要你养成了“状态必须生成新快照”的意识这些边界问题就会提前规避掉大部分。我个人在经历了不知道多少次 setState 之后读旧值的痛苦之后给自己定了一个开发铁律凡是参与事件决策或异步逻辑的值第一时间问自己“这个值需要在当前渲染中使用吗”。如果不在当前渲染中使用优先放到局部变量或 ref如果必须参与渲染才放 state。这个判断比背诵任何 API 都管用。还有一个小技巧分享给你遇到状态更新异常先检查回调函数的“出生地”也就是定义它的那次渲染。那个地方决定了它看到哪个快照。问题看起来千变万化但想来想去核心还是那一句话useState 给你的是快照不是活水。

相关新闻

SpringerNature期刊LaTeX投稿全攻略:模板选择与编译避坑指南

SpringerNature期刊LaTeX投稿全攻略:模板选择与编译避坑指南

说到springernature期刊LaTeX写作,第一次上手的人很容易被模板包整懵。我长期帮课题组处理投稿前的排版与系统校验,经手过相当多SN系(即springernature这个出版体系下)期刊的稿件。这个体系对LaTeX的支持很完整,官方模…

2026/10/10 4:33:11 阅读更多 →
React渲染快照模型:setState为何总读到旧值?

React渲染快照模型:setState为何总读到旧值?

做 React 开发的人,基本都撞上过这种诡异时刻:在事件处理函数里连续写了三遍setCount(count 1),结果页面上数字只跳了 1;或者明明刚setState完,紧跟着一行console.log(state),打印出来的却是旧值&#xff…

2026/10/10 4:32:54 阅读更多 →
新模型Opus 5.5与Sonnet 5.5上线,为何你还不能用?附接入和排查指南

新模型Opus 5.5与Sonnet 5.5上线,为何你还不能用?附接入和排查指南

最近圈子里聊得最多的,就是 Antigravity 平台一口气上线了 Opus 5.5 和 Sonnet 5.5 这两个新模型。实际去后台看了一眼,发现情况很有意思:模型确实上架了,但不少朋友的账号点进去什么都没有,有些人的控制台倒是能看到&…

2026/10/10 4:31:53 阅读更多 →

最新新闻

统一登录与单点登录实战:网关与认证中心的搭建全解

统一登录与单点登录实战:网关与认证中心的搭建全解

这段时间我一直在折腾一件事:把我们内部几个各自为战的业务系统,统一到一个登录入口底下。项目代号倒是很形象,sward 负责守门,soular 负责认人。说白了,sward 是一个网关层,soular 是一个身份认证中心&…

2026/10/10 14:52:58 阅读更多 →
打印机驱动下载安装完整指南:从官网获取到故障排查

打印机驱动下载安装完整指南:从官网获取到故障排查

1. 打印机驱动安装这件事,为什么值得单独写一篇完整指南打印机驱动下载安装,听起来像是电脑入门级别的操作,但实际工作中我见过太多人在这上面翻车。有人下载了错误的驱动版本导致打印机频繁脱机,有人装完驱动后扫描功能死活调不出…

2026/10/10 14:52:58 阅读更多 →
基于SpringBoot+Vue+MySQL的船舶监造管理系统实战解析

基于SpringBoot+Vue+MySQL的船舶监造管理系统实战解析

做船舶监造的人肯定都懂,监造不是坐在办公室看看图纸就行,真正业务一铺开,报验单、现场见证、NCR整改闭环、试验计划、图纸送审,每个环节都是需要“有人跟、有记录、有闭环”的。早几年我在船厂和监造组干活时,全靠Exc…

2026/10/10 14:52:58 阅读更多 →
Zen Cart PayPal跳转插件:解决掉单与IPN异步通知问题

Zen Cart PayPal跳转插件:解决掉单与IPN异步通知问题

简介:面向ZenCart商城的PayPal跳转插件,用于打通ZenCart与PayPal支付接口,实现用户在付款时从商店页面到支付网关再返回结果页的完整跳转流程,适合使用ZenCart开展跨境或外贸电商的商家、开发者及运维人员。该插件压缩包共24个文件…

2026/10/10 14:52:58 阅读更多 →
线程池线程数配置实战:CPU密集型与IO密集型任务调优策略

线程池线程数配置实战:CPU密集型与IO密集型任务调优策略

1. 先分清任务在“算”还是在“等”——这是所有配置的起点1.1 CPU 密集型和 IO 密集型的本质差异多线程编程里有一个被问得最多的问题:线程池到底配多少个线程?我几乎每一次都会先反问他一句:你的任务是 CPU 密集型还是 IO 密集型&#xff1…

2026/10/10 14:52:57 阅读更多 →
Windows下OSGeo4W安装PDAL避坑指南:从环境配置到LAZ v1.4实测

Windows下OSGeo4W安装PDAL避坑指南:从环境配置到LAZ v1.4实测

简介:本资源是面向GIS开发者、遥感工程师及三维点云处理从业者的PDAL库离线安装包,专为解决Windows环境下因网络限制导致OSGeo4W官网下载PDAL失败或缓慢的痛点。压缩包完整封装了OSGeo4W64 64位安装环境及PDAL核心组件,并预集成CloudCompare兼…

2026/10/10 14:51:56 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →