React加载组件时禁用动画,仅在响应式断点触发动画
解决React组件首次加载时动画自动触发的问题
这个问题我之前也碰到过!核心原因是首次加载时你的响应式逻辑会直接检查当前窗口尺寸,要是刚好小于800px,动画触发条件就满足了,自然会自动播放。咱们可以通过区分「首次加载」和「用户主动调整窗口尺寸」这两种场景来解决,给你两种方案适配不同的组件类型:
方案一:类组件(对应你提到的带有render()的Test组件)
我们可以添加一个状态标记组件是否完成首次挂载,只有挂载完成后,窗口尺寸变化触发断点时才执行动画:
class Test extends React.Component { // 初始化状态:当前是否为移动端尺寸,以及是否完成首次挂载 state = { isMobile: window.innerWidth < 800, hasMounted: false }; componentDidMount() { // 挂载后添加resize监听 window.addEventListener('resize', this.handleResize); // 标记组件已完成首次挂载 this.setState({ hasMounted: true }); } componentWillUnmount() { // 组件卸载时移除监听,避免内存泄漏 window.removeEventListener('resize', this.handleResize); } handleResize = () => { const newIsMobile = window.innerWidth < 800; // 仅当组件已挂载,且尺寸状态发生变化时,才触发动画 if (this.state.hasMounted && newIsMobile !== this.state.isMobile) { this.setState({ isMobile: newIsMobile }, () => { // 这里执行你的动画逻辑 this.triggerDivAnimation(); }); } else { // 只是更新尺寸状态,不触发动画 this.setState({ isMobile: newIsMobile }); } }; triggerDivAnimation = () => { // 获取main-content下的div,添加动画类 const targetDivs = document.querySelectorAll('.main-content div'); targetDivs.forEach(div => div.classList.add('rearrange-animation')); // 动画结束后移除类,方便下次触发时再次生效 setTimeout(() => { targetDivs.forEach(div => div.classList.remove('rearrange-animation')); }, 800); // 这里的时间要和你的CSS动画时长一致 }; render() { const { isMobile } = this.state; return ( <div className={`main-content ${isMobile ? 'mobile-flex-layout' : ''}`}> {/* 你的div内容 */} <div>区块1</div> <div>区块2</div> <div>区块3</div> </div> ); } }
方案二:函数组件(如果后续重构为Hooks写法)
用useRef来标记是否完成首次挂载,结合useEffect处理resize监听:
import React, { useState, useEffect, useRef } from 'react'; const Test = () => { const [isMobile, setIsMobile] = useState(window.innerWidth < 800); // useRef存储挂载状态,不会触发组件重渲染 const hasMounted = useRef(false); useEffect(() => { const handleResize = () => { const newIsMobile = window.innerWidth < 800; if (hasMounted.current && newIsMobile !== isMobile) { setIsMobile(newIsMobile); triggerDivAnimation(); } else { setIsMobile(newIsMobile); } }; window.addEventListener('resize', handleResize); // 挂载完成后更新标记 hasMounted.current = true; // 清理函数:移除监听 return () => window.removeEventListener('resize', handleResize); }, [isMobile]); const triggerDivAnimation = () => { const targetDivs = document.querySelectorAll('.main-content div'); targetDivs.forEach(div => div.classList.add('rearrange-animation')); setTimeout(() => { targetDivs.forEach(div => div.classList.remove('rearrange-animation')); }, 800); }; return ( <div className={`main-content ${isMobile ? 'mobile-flex-layout' : ''}`}> <div>区块1</div> <div>区块2</div> <div>区块3</div> </div> ); }; export default Test;
额外优化建议
如果你的动画是通过CSS类控制的,也可以在render时直接根据挂载状态和尺寸状态决定是否添加动画类,比如:
{/* 类组件render里的main-content */} <div className={`main-content ${isMobile ? 'mobile-flex-layout' : ''} ${this.state.hasMounted && isMobile ? 'animate-on-resize' : ''}`}>
这样能更精准地控制动画的触发时机,避免不必要的DOM操作。
内容的提问来源于stack exchange,提问作者Jolly




