如何正确使用 React.memo 与 Framer Motion 和 Next.js 图像组件

问题描述 投票:0回答:1

我正在开发一个 Next.js 项目,我需要使用

Image
中的
next/image
组件显示英雄图像,并使用
framer-motion
为它们设置动画。我还想通过使用 React.memo 来优化性能 但是,当英雄道具为
null
时,我遇到了图像无法正确渲染的问题。当只有一个更新时,所有这些都会变得动画。

相关代码如下:

import { motion } from "framer-motion";
import Image from "next/image";
import React from "react";

interface Hero {
  name: string;
  img: string;
}

const HeroImage = React.memo(
  ({ hero, index }: { hero: Hero | null; index: Number }) => {
    return (
      <motion.div
        key={"hero" + index}
        className="relative w-full h-full"
        layoutId={"hero" + index}
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      >
        <Image
          key={"hero" + index}
          src={hero?.img || ""}
          alt={hero?.name || "Placeholder"}
          layout="fill"
          objectFit="cover"
          draggable={false}
          style={{
            visibility: hero ? "visible" : "hidden",
          }}
        />
      </motion.div>
    );
  }
);

const HeroCard = React.memo(
  ({ hero, index }: { hero: Hero | null; index: Number }) => {
    return (
      <div
        className="relative overflow-hidden rounded flex-grow bg-cover"
        style={{
          backgroundImage: `url('/placeholder.png')`,
        }}
      >
        <HeroImage hero={hero} index={index} />
        <div className="absolute bottom-0 left-0 right-0 bg-black/70 text-white text-center py-1">
          {hero?.name}
        </div>
      </div>
    );
  }
);

export { HeroImage, HeroCard };

任何帮助或建议将不胜感激!

我想要在选择英雄时有一个向上滑动的动画,但是当我选择一个英雄时它工作正常,但如果我选择另一个英雄,所有以前的也会变得动画。我只想要更新的动画

javascript reactjs node.js next.js framer-motion
1个回答
0
投票

您可以将 Motion.div 包装在 AnimatePresence 中,以便它仅更新当前渲染或更新的英雄图像。在安装或卸载时对每个图像应用初始、动画和退出。

<AnimatePresence>
    {hero && (
      <motion.div
        key={hero.name + index} 
        className="relative w-full h-full"
        layoutId={"hero" + index}
        initial={{ y: 50, opacity: 0 }} 
        animate={{ y: 0, opacity: 1 }}
        exit={{ y: 50, opacity: 0 }}
        transition={{ duration: 0.5 }}
      >
        <Image
          src={hero.img}
          alt={hero.name}
          layout="fill"
          objectFit="cover"
          draggable={false}
        />
      </motion.div>
    )}
  </AnimatePresence>
);

}

© www.soinside.com 2019 - 2024. All rights reserved.