在React/Next.js中更改mouseover/mouseout的图像源



我使用的技术:

Next.jsStyled-Components打印稿

我想做的:

当我将鼠标悬停在包装它的父div (Card)上时,我希望将图像更改为另一个。

我的解决方案:

我设法做到了使用useState像这样:

const [isHovering, setIsHovered] = useState(false);
const [isHovering2, setIsHovered2] = useState(false);
const [isHovering3, setIsHovered3] = useState(false);


<Card1>
<Card
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<IconWrapper>
{isHovering ? (
<Image layout="fill" src={image1OnHover} />
) : (
<Image layout="fill" src={image1} />
)}
</IconWrapper>
<CardText>
<h4>Title</h4>
<p>
Dorem Ipsum.
</p>
</CardText>
</Card>
</Card1>
<Card2>
<Card
onMouseEnter={() => setIsHovered2(true)}
onMouseLeave={() => setIsHovered2(false)}
>
<IconWrapper>
{isHovering2 ? (
<Image layout="fill" src={image2OnHover} />
) : (
<Image layout="fill" src={image2} />
)}
</IconWrapper>
<CardText>
<h4>Title</h4>
<p>
Dorem Ipsum
</p>
</CardText>
</Card>
</Card2>
<Card3>
<Card
onMouseEnter={() => setIsHovered3(true)}
onMouseLeave={() => setIsHovered3(false)}
>
<IconWrapper>
{isHovering3 ? (
<Image layout="fill" src={image3OnHover} />
) : (
<Image layout="fill" src={image3} />
)}
</IconWrapper>
<CardText>
<h4>Title</h4>
<p>
Dorem Ipsum
</p>
</CardText>
</Card>

我想要的:

在我看来,这段代码看起来很糟糕,并没有真正遵循DRY原则。

它工作,但我不认为垃圾邮件useStates是一个好主意(如果有100张图片要改变…

我一直在网上搜索一些更好的想法,但我只找到了类似于我所编码的和单一图像的例子。这里的问题是,如果我只使用一种状态,那么所有的图像将同时更改-这迫使我为添加到页面的每个元素使用单独的钩子。

这是我在stackoverflow上的第一个请求-如果我的帖子不符合标准,我道歉-希望它能做到;)

另一个选择是创建一个组件来处理状态,然后将两个图像选项传递给它。下面是一个简单组件的示例:https://codesandbox.io/s/hoverimage-ldscek?file=/src/OnHoverImage.js:40-449。然后,你就可以映射那个组件,并且可以随心所欲地多次显示那个组件。

export const OnHoverImage = ({ hoveredImage, image, alt }) => {
const [hover, setHover] = useState(false);
return (
<div
style={{ width: "200px", height: "200px" }}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{hover ? (
<img src={image} alt={alt} />
) : (
<img src={hoveredImage} alt={alt} />
)}
</div>
);
};

映射图像将看起来像这样:

<div>
{arrayOfImages.map((el) => (
<OnHoverImage
alt={el.alt}
hoveredImage={el.hoverImage}
image={el.image}
/>
))}
</div>

当然有很多方法可以做到这一点。其中一种方法是使用一个表示所有图像的状态:

const images = [...];
const Component = (props) => {
const [imageStates, setImageStates] = useState({});
const setImageHoveringState = (imageId, state) => {
setImageStates({
...imageStates,
imageId: state,
});
};
return (
<div>
{images.map((image) => {
// If the images don't have an ID, just use their index in the array
return (
<Card
key={image.id}
onMouseEnter={() => setImageHoveringState(image.id, true)}
onMouseLeave={() => setImageHoveringState(image.id, false)}
/>
<IconWrapper>
{imageStates[image.id] ? (
<Image layout="fill" src={image2OnHover} />
) : (
<Image layout="fill" src={image2} />
)}
</IconWrapper>
</Card>
);
})}
</div>
);
};

无论是单一状态还是不同状态都是好的。这取决于你的喜好。实际上不同状态比对象状态更明确。

对象:

const [state, useState] = useState({ ... })

不同国家

const [state1, useState] = useState()
const [state1, useState] = useState() 
const [state1, useState] = useState() 

另一个更清晰的例子

有单独的变量

const num1 = 1
const num2 = 2
const num3 = 3

或有一个对象但有不同的属性。

const nums = {
num1: 1,
num2: 2,
num3: 3
}