transition初次渲染不生效,根本原因是浏览器未获取起始快照:dom插入与样式设置同属一个microtask,跳过样式计算,导致无起始值可插值。

React 里直接用 transition 写 CSS 动画,最常踩的坑不是“写错了”,而是“根本没触发”——浏览器压根没启动过渡引擎。
transition 第一次渲染不生效
现象是元素“啪”一下闪现,DevTools 里看不到 transition timeline。这不是 CSS 写错,而是浏览器没拿到起始快照。
- DOM 插入和样式设置在同一个 microtask 里完成,浏览器来不及做样式计算 → 没有“起始值”可插值
- 比如
opacity初始没声明(或由 JS 动态加 class 后才设),浏览器采样到的是opacity: 1,再设1就没变化 - 强制触发重排可补救:
el.offsetHeight或getComputedStyle(el).opacity,但别滥用,会 layout thrashing - 更稳妥的做法:让初始状态通过 CSS 类明确定义,比如
.fade-enter { opacity: 0; },再用 JS 控制类切换
CSSTransition 的 nodeRef 必须显式传
React 18 严格模式下 findDOMNode 已废弃,CSSTransition 不再自动找 DOM 节点,漏传 nodeRef 就会丢动画、报警告。
-
nodeRef和子元素的ref必须指向同一个useRef实例 - 不能只传
ref给子元素而漏掉nodeRef属性,否则类名注入时机错乱 - 示例:
const nodeRef = useRef(null); <csstransition noderef="{nodeRef}"><div ref="{nodeRef}">...</div></csstransition>
timeout 和 CSS transition-duration 必须对齐
timeout 不是“动画时长”,而是“React 等待 CSS 动画结束的超时阈值”。它必须 ≥ 对应 CSS 的 transition-duration,否则 React 会提前移除类名,动画被截断。
- enter/exit 时间不同?用对象:
timeout={{ enter: 300, exit: 500 }} - CSS 里写了
transition: all 0.3s ease,JS 就不能设timeout={200} - 多个属性过渡时间不一致?取最大值,或拆成独立
transition声明
classNames 前缀和实际 class 名必须严格匹配
写 classNames="fade",就得有 .fade-enter、.fade-enter-active 这些类——少一个,动画就卡在中间态。
- 别依赖默认前缀(如
transition-),react-transition-groupv4+ 不再内置默认 - 用对象模式更可控:
classNames={{ enter: 'fade-in', enterActive: 'fade-in-active', exit: 'fade-out' }} - 检查 DevTools 元素面板,确认类名是否真的被加到了 DOM 上——有时候是拼写错误,比如
fade-enterr
真正麻烦的从来不是怎么写动画,而是怎么让浏览器“看见起始帧”。CSS transition 看似简单,但它高度依赖渲染流水线的节奏,而 React 的批量更新和虚拟 DOM 会让这个节奏变得隐蔽。动手前先看一眼 computed style,比猜半天更有效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











