skip to Main Content

I’m trying to create a react component (NextJS), which is a hexagon with an image inside it. The component should render the image that was sent as a prop. However, when I try to use multiple components with different images in the HeagonWall, all hexagons render the image of the first instance of that component instead of rendering both images accordingly. How can I solve this issue?

//hexagon-tile.tsx

interface HexagonTileProp {
  imageLink: string,
  imageId: string
}

export default function HexagonTile({ imageLink, imageId }: HexagonTileProp) {
  return (
    <div>
      <svg height='387' viewBox='0 0 595 687' fill='none' xmlns='http://www.w3.org/2000/svg' xmlnsXlink='http://www.w3.org/1999/xlink'>
        <path d='M297.5 0L594.98 171.75V515.25L297.5 687L0.0202637 515.25V171.75L297.5 0Z' fill='url(#pattern0)' />
        <defs>
          <pattern id='pattern0' patternContentUnits='objectBoundingBox' width='1' height='1'>
            <use xlinkHref={`#${imageId}`} transform='translate(-0.3) scale(0.000625)' />
          </pattern>
          <image id={imageId} width='2560' height='1600' xlinkHref={imageLink} />
        </defs>
      </svg>
    </div>
  );
}
//hexagon-wall.tsx

export default function HexagonWall() {
  return (
    <div>
      <HexagonTile imageLink='https://cdn.test.com/testimg/testimg-1.jpg' imageId={crypto.randomUUID()} />
      <HexagonTile imageLink='https://cdn.test.com/testimg/testimg-2.jpg' imageId={crypto.randomUUID()} />
    </div>
  );
}

The expected outcome should have different images inside two hexagons. But this is the actual outcome:

enter image description here

2

Answers


  1. You should either be auto generating the image and pattern ids, or passing id in as a prop. You have hardcoded them for every image / pattern, so every svg will just take the first image / pattern with that id in the DOM.

    You can use crypto.randomUUID() to generate a unique id.

    Note support for this function: https://caniuse.com/mdn-api_crypto_randomuuid

    Note xlink:href is deprecated you can just use href.

    export default function HexagonTile({ imageLink }: HexagonTileProp) {
      const id = crypto.randomUUID();
      const imageId = 'image' + id;
      const useHref = '#' + imageId;
      const patternId = 'pattern' + id;
      const pathFill = 'url(#' + patternId + ')';
      return (
        <div>
          <svg
            height="387"
            viewBox="0 0 595 687"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
            xmlnsXlink="http://www.w3.org/1999/xlink"
          >
            <path
              d="M297.5 0L594.98 171.75V515.25L297.5 687L0.0202637 515.25V171.75L297.5 0Z"
              fill={pathFill}
            />
            <defs>
              <pattern
                id={patternId}
                patternContentUnits="objectBoundingBox"
                width="1"
                height="1"
              >
                <use href={useHref} transform="translate(-0.3) scale(0.000625)" />
              </pattern>
              <image id={imageId} width="2560" height="1600" href={imageLink} />
            </defs>
          </svg>
        </div>
      );
    }
    

    Stackblitz: https://stackblitz.com/edit/stackblitz-starters-vq1t45?file=src%2FApp.tsx

    Login or Signup to reply.
  2. You’re defining a duplicate pattern id.

    Fix it by using your id props :

    <svg viewBox="0 0 595 687">
      <path
        d="M297.5 0L594.98 171.75V515.25L297.5 687L0.0202637 515.25V171.75L297.5 0Z"
        fill={`url(#pattern${id})`}
      />
      <defs>
        <pattern
          id={`pattern${id}`}
          patternContentUnits="objectBoundingBox"
          width="1"
          height="1"
        >
          <use
            href={`#${id}`}
            transform="translate(-0.3) scale(0.000625)"
          />
          <image id={id} width="2560" height="1600" href={imageLink} />
        </pattern>
      </defs>
    </svg>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search