使用framer-motion的motion.span组件出现TypeError问题求助
解决framer-motion中motion.span引发的TypeError: Cannot set properties of null (setting 'textContent')错误
问题描述
使用framer-motion的motion.span组件时,出现TypeError: Cannot set properties of null (setting 'textContent')错误。该错误不会阻止Web应用运行,但会在一段时间后突然弹出在屏幕上,错误由animationProjectsCount函数中的onUpdate回调引发。
错误原因
- ref临时为空:
whileInView触发动画时,可能因组件重渲染、视图状态变化等原因,projectCount.current还未绑定到DOM元素或已临时变为null,此时直接赋值textContent就会报错。 - 动画未清理:组件卸载后,之前启动的动画可能仍在后台运行,此时
projectCount.current已经是null,执行赋值操作触发错误。 - 重复触发动画:元素多次进入视图时,动画会重复启动,增加了ref为空的概率。
解决方案
1. 给ref添加空值判断
在onUpdate回调中先检查projectCount.current是否存在,再执行赋值操作,避免空值错误:
const animationProjectsCount = () => { animate(0, 30, { duration: 1, onUpdate: (v) => { if (projectCount.current) { // 先确认ref指向有效DOM元素 projectCount.current.textContent = v.toFixed(); } } }) }
2. 组件卸载时清理动画
使用useRef保存动画控制对象,在组件卸载时停止动画,防止组件销毁后动画仍在运行:
import React, { useRef, useEffect } from 'react'; import { animate, motion } from "framer-motion"; import Timeline from './Timeline'; const Home = () => { const projectCount = useRef(null); const animationControls = useRef(null); // 保存动画控制对象 const animationProjectsCount = () => { animationControls.current = animate(0, 30, { duration: 1, onUpdate: (v) => { if (projectCount.current) { projectCount.current.textContent = v.toFixed(); } } }) } useEffect(() => { // 组件卸载时停止动画 return () => { if (animationControls.current) { animationControls.current.stop(); } } }, []) return ( <div id='about'> <div className="abtSections"> <div className="abtLeft"> <h1 className='abtHeader'>About</h1> <p>As I strive to achieve my goal of becoming a full-stack developer, I have acquired valuable experience through the completion of various projects at a beginner level, and my accumalated years of programming and project work. Moreover, I possess a notable self aptitude for self-directed learning and am able to apply myself for acquiring new skills at a constrained time frame.</p> </div> <div className="abtRight"> <Timeline /> </div> <div style={{ clear: "both" }}></div> </div> <div className='projectsDone'> <p className='number'> +<motion.span ref={projectCount} whileInView={animationProjectsCount}></motion.span> </p> <span className='done'>Projects Done</span> </div> </div> ) } export default Home
3. 限制动画只触发一次
给whileInView添加viewport={{ once: true }}配置,确保动画仅在元素第一次进入视图时触发,减少重复执行带来的风险:
<motion.span ref={projectCount} whileInView={animationProjectsCount} viewport={{ once: true }}></motion.span>
综合优化建议
将以上三种方案结合使用:空值判断避免即时错误,动画清理防止组件卸载后报错,单次触发减少不必要的动画执行,彻底解决该问题。
内容的提问来源于stack exchange,提问作者Aaryan02
相关产品推荐
相关产品推荐

