我想用react spring构建一个可重用的动画组件。到目前为止,我拥有的是:
代码沙箱
const Fade = ({
show,
as = "div",
children
}: {
show: boolean;
as?: keyof JSX.IntrinsicElements;
children: React.ReactNode;
}) => {
const transitions = useTransition(show, null, {
from: { position: "absolute", opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
unique: true
});
const AnimatedComponent = animated[as];
return (
<>
{transitions.map(({ item, key, props }) => {
if (!item) {
return null;
}
return (
<AnimatedComponent key={key} style={props}>
{children}
</AnimatedComponent>
);
})}
</>
);
};
然而,现在存在一个问题,即动画组件引入了";"副作用";,添加一个";div";包裹在我想要动画的孩子身上。这会导致现有组件出现样式问题,需要进行大量更改。
因此,作为一种变通方法,我尝试使用animated
作为函数,并将子元素作为非实例化的react元素传递。但随后会出现明显的嘎嘎声,动画没有完成,有时会在中途停止,例如,检查动画元素,并注意到不透明度往往会停止在0.98883393,而不是1。
代码沙箱
const Fade = ({
show,
children
}: {
show: boolean;
children: React.ReactElement;
}) => {
const transitions = useTransition(show, null, {
from: { position: "absolute", opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
unique: true
});
// Here's the change. We wrap children in a functional component and clone
// children inside
const AnimatedComponent = animated(({ style }) =>
React.cloneElement(children, { style })
);
return (
<>
{transitions.map(({ item, key, props }) => {
if (!item) {
return null;
}
return (
<AnimatedComponent key={key} style={props}>
{children}
</AnimatedComponent>
);
})}
</>
);
};
我注意到,引入额外的";div";包装器似乎是一些基于动画的库的副作用,比如react spring和framer motion
有没有一种建议的方法可以用react spring构建可重复使用的动画组件,而不会带来引入额外DOM元素的副作用
这是react-spring
的旧版本,从那以后情况发生了变化,因此很难准确地解决为什么opacity
会出现这种无法到达1.0
的奇怪行为。尽管如此,控制台中也有一个关于更新未安装组件的警告,并且key
属性始终是undefined
,所以我不确定您是否正确使用了转换。但是由于api文档已经不复存在,因此很难进行故障排除。
尽管如此,我CAN告诉您,没有必要在动画内容周围添加额外的包装元素。在第一种情况下,您明确地告诉react-spring
添加一个元素(animated.XXX
(,它当然会这样做。在您的第二个(坏的(示例中,没有包装器,我认为如果您研究如何在旧版本中使用useTransition
,您可以实现这一点。
然而,您应该知道,react-spring
在最佳状态下使用ref来更新React之外的元素。这就是为什么animated
提供的所有基本HTML元素(animated.div
、animated.span
等(都具有您所看到的这种包装行为。如果你使用animated
来包装你自己的组件,你基本上有两个选择:
- 确保您的自定义组件可以保存一个ref,并将
animated
中的任何给定ref提供给它(使用forwardRef
(。现在,您的组件不会一直重新发送,而是只发送一次,并且更新将在React之外处理。通过这种方法,您可以确定要将ref赋予哪个元素(而不是使用包装器来简化react-spring
( - 不要让自定义组件引用并接受组件将在每个动画帧上重新渲染一次(这就是您的示例中发生的情况,记录每个渲染以验证这一点(。从性能的角度来看,这是次优的,但仍然有效
总之,这并不能解释opacity
的奇怪之处,但它确实解释了为什么react-spring
更喜欢使用包装器组件,因为这样它可以保证以有效的方式动画化该元素的所有内容。幸运的是,react-spring
还为您提供了选择所需元素类型的选项。