如何在React+TypeScript中将framer-motion应用于多态组件?
解决framer-motion在多态React组件中的类型问题
你遇到的错误是因为motion对象不支持通过动态属性名(比如motion.Component)创建组件,正确方式是使用motion()工厂函数包装动态组件。以下是完整修复方案:
步骤1:更新类型定义
引入framer-motion的MotionProps并合并到组件Props中,确保动画属性能被TypeScript正确识别:
import React, { DetailedHTMLProps } from 'react'; import { motion, MotionProps } from 'framer-motion'; type ButtonProps = DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> & MotionProps; type AnchorProps = DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement> & MotionProps; type Props = (ButtonProps | AnchorProps) & { as?: 'button' | 'a'; secondary?: boolean; };
步骤2:修改组件实现
用motion()函数包装动态Component,替代错误的motion.Component写法:
const Button: React.FC<Props> = (props: Props) => { const { as: Component = 'button', secondary, className, ...restProps } = props; // 使用motion()工厂函数创建支持动画的动态组件 const MotionComponent = motion(Component); const baseClassName = secondary ? `font-bold text-lg lg:mx-4 sm:mx-2 flex items-center gap-1 select-none` : `font-bold text-lg px-4 py-2 select-none rounded-xl text-white bg-primary-base hover:bg-primary-hover mx-4`; return ( <MotionComponent className={`${baseClassName} ${className || ''}`} {...restProps} > {props.children} </MotionComponent> ); }; export default Button;
关键说明
motion()工厂函数:framer-motion提供的创建自定义动态组件的方法,接受HTML标签名(如'button'、'a')或React组件,返回支持动画属性的motion版本组件。- 类型合并:将
MotionProps合并到基础Props中,确保你能传递animate、transition等动画属性,同时保持TypeScript类型检查正常。 - 简化props处理:通过解构赋值分离自定义属性,避免手动删除属性的繁琐操作,代码更简洁。
现在你可以正常使用带动画的多态组件:
<Button as="a" href="/" animate={{ scale: 1.05 }} whileHover={{ scale: 1.1 }}> 链接按钮 </Button> <Button secondary animate={{ opacity: 0.9 }} whileTap={{ opacity: 0.7 }}> 次要按钮 </Button>
内容的提问来源于stack exchange,提问作者Alexxino
相关产品推荐
相关产品推荐

