我想用 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>
);
})}
</>
);
};
但是,现在存在动画组件引入“副作用”的问题,即在我想要动画的 child 周围添加一个“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 文档已不复存在,因此很难进行故障排除。
尽管如此,我可以告诉您,没有必要在您的动画内容周围添加额外的包装器元素。在第一种情况下,您明确告诉 react-spring
添加一个元素 (animated.XXX
),它当然会这样做。在你的第二个(损坏的)例子中,没有包装器,我认为如果你研究如何在那个旧版本中使用 useTransition
,你可以让它工作。
但是你应该知道 react-spring
在其最佳状态下使用 ref 来更新 React 之外的元素。这就是为什么 animated
(animated.div
、animated.span
等...)提供的所有基本 HTML 元素都具有这种包装行为看到。如果你使用 animated
来包装你自己的组件,你基本上有两种选择:
- 确保您的自定义组件可以保存一个 ref 并将
animated
中的任何给定 ref 提供给它(使用forwardRef
)。现在您的组件将不会一直重新渲染,而只会重新渲染一次,并且更新将在 React 之外处理。使用此方法,您可以确定要将引用提供给哪个元素(而不是react-spring
使用包装器为您简化此操作)。 - 不要让您的自定义组件采用引用并接受您的组件将在每个动画帧上重新渲染一次(这就是您的示例中发生的情况,记录每个渲染以验证这一点)。从性能的 Angular 来看,这是次优的,但仍然有效。
总而言之,这并不能解释 opacity
的奇怪之处,但它确实解释了为什么 react-spring
更喜欢使用包装器组件, 因为这样它可以保证它可以以有效的方式为该元素的所有内容设置动画。幸运的是,react-spring
还为您提供了选择所需元素类型的选项。
关于javascript - 使用 react-spring 构建可重用的动画组件而不渲染包装元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66805256/