繁体   English   中英

使用 react-spring 构建可重用的 Animation 组件,无需渲染包装器元素

[英]Build reusable Animation component with react-spring without rendering a wrapper element

我想用react-spring构建一个可重复使用的 animation 组件。 这是我到目前为止所拥有的:

密码箱

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>
        );
      })}
    </>
  );
};

但是,现在存在一个问题,animation 组件引入了“副作用”,在我想要动画的孩子周围添加了一个“div”包装。 这会导致现有组件出现样式问题,需要进行大量更改。

因此,作为一种解决方法,我尝试将animated用作 function,并将子元素作为非实例化的反应元素传递。 但是随后会出现明显的卡顿,并且 animation 没有完成并有时会在中途停止,例如,检查动画元素,并注意到不透明度倾向于停止在 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-springframer-motion )的副作用

有没有建议的方法来构建可重复使用的 animation 组件与 react-spring 没有引入额外 DOM 元素的副作用

这是react-spring的旧版本,从那时起事情发生了变化,所以很难准确地解决为什么你有这种奇怪的行为, opacity没有达到1.0 尽管如此,您在控制台中也会收到有关更新未安装组件的警告,并且key属性始终undefined ,因此我不确定您是否正确使用了转换。 但是由于 api 文档不再存在,因此很难进行故障排除。

尽管如此,我可以告诉你,没有必要在你的动画内容周围添加一个额外的包装元素。 在第一种情况下,您明确告诉react-spring添加一个元素( animated.XXX ),它当然会这样做。 在您的第二个(损坏的)示例中,没有包装器,如果您研究如何在旧版本中使用useTransition ,我认为您可以让它工作。

然而,你应该知道react-spring在最好的时候使用 ref 来更新 React 之外的元素。 这就是为什么animated提供的所有基本 HTML 元素( animated.divanimated.span等...)都具有您所看到的这种包装行为。 如果你使用animated来包装你自己的组件,你基本上有两种选择:

  • 确保您的自定义组件可以保存一个 ref 并提供任何给定的 ref 从animated到它(使用forwardRef )。 现在你的组件不会一直重新渲染,而只会重新渲染一次,并且更新将在 React 之外处理。 使用这种方法,您可以确定要将 ref 提供给哪个元素(而不是react-spring使用包装器为您简化此操作)。
  • 不要让您的自定义组件获取 ref 并接受您的组件将在每个 animation 帧上重新渲染一次(这就是您的示例中发生的情况,记录每个渲染以验证这一点)。 从性能的角度来看,这是次优的,但仍然有效。

总而言之,这并不能解释opacity的奇怪之处,但它确实解释了为什么react-spring更喜欢使用包装器组件,因为这样它可以保证它可以为该元素的所有内容设置动画一种有效的方式。 幸运的是, react-spring还为您提供了选择所需元素类型的选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM