React文本切换组件切换方向后初始滚动方向异常求助
React文本切换滚动方向初始错误修复
问题场景
实现了一个文本段落切换组件,核心需求:
- 初始显示第1段文本
- 正向切换(如1→2→3):旧文本向上滚出视野,新文本从底部滑入
- 反向切换(如3→2→1):旧文本向下滚出视野,新文本从顶部滑入
当前问题:第一次切换方向时(比如从2切回1),滚动方向错误,后续操作恢复正常。
问题根源
问题出在WorkProcessText组件的状态更新逻辑:
- 用
useState存储direction,状态更新是异步的,当activeKey变化时,useLayoutEffect里更新direction,但motion组件渲染时还没拿到最新的方向值,导致第一次动画用了旧方向 - 用
displayedText作为motion.p的key,如果文本重复会导致动画不触发,虽然当前示例文本不重复,但这是潜在隐患
修复方案
核心修改点
- 用同步更新的ref替代
useState存储滚动方向,避免异步状态更新的延迟 - 用唯一的
activeKey作为motion.p的key,确保每次切换都能正确触发动画
修复后的WorkProcessText.js
import React, { useRef, useLayoutEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; const WorkProcessText = ({ displayedText, activeKey }) => { const prevKeyRef = useRef(activeKey); const directionRef = useRef("up"); // 用ref同步存储方向 useLayoutEffect(() => { const prevKey = prevKeyRef.current; // 计算切换方向并更新ref if (activeKey > prevKey) { directionRef.current = "up"; } else if (activeKey < prevKey) { directionRef.current = "down"; } prevKeyRef.current = activeKey; }, [activeKey]); return ( <AnimatePresence mode="wait"> <motion.p key={activeKey} // 使用唯一的activeKey作为动画触发标识 className="text-s text-center w-[90%]" initial={{ y: directionRef.current === "up" ? 300 : -300 }} animate={{ y: 0 }} exit={{ y: directionRef.current === "up" ? -300 : 300 }} transition={{ duration: 0.3, ease: "easeInOut" }} > {displayedText} </motion.p> </AnimatePresence> ); }; export default WorkProcessText;
可选优化(简化主组件逻辑)
主组件中可以不用单独维护displayedText状态,直接通过activeKey从textOptions中获取文本,减少状态冗余:
// WorkProcess.jsx 修改部分 function WorkProcess() { const [activeItem, setActiveItem] = useState(textOptions[0].key); // 直接通过activeItem匹配文本 const displayedText = textOptions.find(item => item.key === activeItem).text; const handleListItemClick = (key) => { setActiveItem(key); }; return ( // ... 其余结构不变 <WorkProcessList activeItem={activeItem} handleListItemClick={handleListItemClick} textOptions={textOptions} /> ); } // WorkProcessList.js 修改onClick传参 <li key={key} onClick={() => handleListItemClick(key)} // ... 其余class不变 > {title} </li>
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

