Not sure exactly how to describe this. I have a grid of cards each displaying a different game and I'd like to set each background-image to an image of the game. Here is the code I have so far:
const games = [
{
id: 1,
background: '../images/game1.png',
name: 'Game 1',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vel sapien arcu. Donec sapien eros, efficitur blandit dui vitae, imperdiet consectetur nibh.',
},
{
id: 2,
background: '../images/game2.png',
name: 'Game 2',
description:
'Nunc efficitur tincidunt malesuada. Pellentesque blandit sapien sed orci tristique molestie. Donec ut metus a sapien gravida convallis sed maximus neque. Aliquam consequat fringilla porta. Curabitur eget semper tortor.',
},
];
export const GameCard = () => {
const [isOpen, setIsOpen] = useState(null);
return (
<div id="card_wrapper">
{games.map((game) => (
<motion.div
transition={{ layout: { duration: 1, type: 'spring' } }}
layout
onClick={() => setIsOpen(!isOpen)}
key={game.id}
style={{
backgroundImage: `url(${game.background}) no-repeat`,
}}
>
<motion.h2 layout="position"> {game.name} </motion.h2>
{isOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1 }}
>
<p> {game.description} </p>
</motion.div>
)}
</motion.div>
))}
</div>
);
};
Specifically
<motion.div
transition={{ layout: { duration: 1, type: 'spring' } }}
layout
onClick={() => setIsOpen(!isOpen)}
key={game.id}
style={{
backgroundImage: `url(${game.background}) no-repeat`,
}}
>
is where I'm trying to pass the image as a background but it doesn't work.
And save your backgrounds there. This is an example from one of my projects. In my case, I would search for the background images on /assets/background/background.png
.
Using this option (with my folder structure as example), your array would be the following, and you won't have to change the code in your component:
const games = [
{
id: 1,
background: '/assets/background/game1.png',
name: 'Game 1',
description:
'Lorem ipsum ...',
}
];
2th option
Set that property on your CSS. When you set background-image: url(../images/game1.png)
in the style sheet, it will work, because when you set it, the component hasn't been rendered yet. So when it is rendered, the actual URL will be one created by the compiler which will be able to find the image. In order to do that, you would have to create a class, or something like that, for each of the games:
.game1{
background-image: url('../images/game1.png'),
}
<motion.div
transition={{ layout: { duration: 1, type: 'spring' } }}
layout
onClick={() => setIsOpen(!isOpen) && renderImgArr}
key={game.id}
>
Final considerations: I would use the first option. It is much cleaner and will save you to write and apply a lot of custom classes.
CodePudding user response:
Actually your onClick handler just handle open and close, you need define background img first as state on empty array before rendering on jsx, like so
export const GameCard = () => {
const [isOpen, setIsOpen] = useState(null);
const [imgList, setImgList] = useState([]);
const imgRef = useRef()
const renderImgArr = (dataImg) => {
setImgList([dataImg])
/* ....define imgRef ...*/
}
return (
<div id="card_wrapper">
{games.map((game) => (
<motion.div
transition={{ layout: { duration: 1, type: 'spring' } }}
layout
// add renderImg and also possible to add setTimeOut on renderImgArr
onClick={() => setIsOpen(!isOpen) && renderImgArr}
key={game.id}
style={{
backgroundImage: `url(${game.background}) no-repeat`,
}}
>
<motion.h2 layout="position"> {game.name} </motion.h2>
{/* render imgList with isOpen */}
{isOpen && imgList && (
<motion.div
initial={{ opacity: 0 }}
// define ref as a target reference
animate={imageRef.current.target, { opacity: 1 }}
transition={{ duration: 1 }}
>
<p> {game.description} </p>
</motion.div>
)}
</motion.div>
))}
</div>
);
};
This not perfectly work but you can have imagine how it's work, hopefully :)