Search code examples
reactjsarraysinline-styles

How to dynamically set background image to card component from an array?


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}
          class="card"
          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 }}
              class="expand"
            >
              <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}
          class="card"
          style={{
            backgroundImage: `url(${game.background}) no-repeat`,
          }}
        >

is where I'm trying to pass the image as a background but it doesn't work.

Edit showing console : Shows image being passed through but not rendering


Solution

  • Maycie, this is because you are setting the property directly on the DOM. When you render your components and access them on localhost, you are currently on the root folder of your project. So what your code is trying to do is actually go one folder back. It won't work. You have two alternatives:

    1th option

    Save your images on a public folder inside your project. In the same level as your src folder, create a public folder

    enter image description here

    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}
        class="card .game1"
    >
    

    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.