Home > Software engineering >  useSWR to pass dynamic 'Cards' in to a dynamic index on slides in Swiperjs
useSWR to pass dynamic 'Cards' in to a dynamic index on slides in Swiperjs

Time:08-13

I am currently experiencing issues when trying to pass data from my Slider (SwiperJS as parent component) in to my dynamic Card component as a child.

I am using SWR to data fetch from an api endpoint (dummy data) in order to test functionality.

Here is my code...

./components/Slider.js - Parent component

import React, { useState } from 'react'
import { Swiper, SwiperSlide} from 'swiper/react'
import { Virtual, Navigation, FreeMode } from "swiper"
import { SongCard } from './Songcard'
import useSWR from 'swr'

const fetcher = (url) => fetch(url).then((res) => res.json())

// Import Swiper styles
import 'swiper/css';
import 'swiper/css/virtual'
import 'swiper/css/navigation'
import 'swiper/css/free-mode'

export default function Slider() {

  const { data, error } = useSWR('https://api.npoint.io/fdb9617039cbd942c147', fetcher)
  if(!data) return <div className={style.loading}>Loading</div>
  if(error) return <div>Error</div>

 // Create array with dynamic slides
  const slides = Array.from({ length: data.length }).map(
    (el, index) => `Slide ${index   1}`)
  console.log(data.length)

  return (
    <Swiper
      modules={[Virtual, Navigation, FreeMode]}
      slidesPerView={7}
      virtual
      centeredSlides={true}
      initialSlide="3"
      navigation={true}
      grabCursor={true}
      breakpoints={{
        280: {
          slidesPerView: 1,
        },
        360: {
          slidesPerView: 2,
        },
        584: {
          slidesPerView: 3,
        },
        768: {
          slidesPerView: 4,
        },
        1024: {
          slidesPerView: 5,
        },
        1260: {
          slidesPerView: 6,
        },
      }}
      >
      {slides.map((slidecontent, index) => (
        <SwiperSlide key={slidecontent} virtualIndex={index}>
          {data.map((data) =>{
            return <SongCard key={data.songId} />
          })}
        </SwiperSlide>
      ))}
    </Swiper>
  )
}

./components/SongCard.js - Child component

import Image from 'next/image'
import styles from '../styles/Card.module.css'
import Script from 'next/script'

export function SongCard(data) {

  return (
    <section>
      <Script src="https://kit.fontawesome.com/4dcae86ee9.js" crossorigin="anonymous"/>
      <div className={styles.container}>
        <div className={styles.songImg}>
          <div className={styles.imgWrapper}>
            <Image 
              className={styles.songImage}
              priority="true"
              src="/counting.png"
              alt={data.songName}
              width="200px"
              height="200px"
              layout="intrinsic"
              objectPosition="center"
            />
          </div>  
          <div className={styles.songImage}>
            <span><i className="fa-solid fa-fire-flame-curved fa-beat"></i></span>
          </div>
          <div className={styles.songInfo}>
            <p className={styles.songTitle}></p>
            <p className={styles.artistTitle}>{data.screenName}</p>
            <p className={styles.vibes}>{data.songVibeTags}</p>
            <p className={styles.genres}>{data.songGenreTags}</p>
          </div>
          <div className={styles.iconContainer}>
            <span className={styles.likes}>
              <i className="fa-solid fa-thumbs-up"></i>
              <p className={styles.countLikes}>{data.songLikes}</p>
              <i className="fa-solid fa-play"></i>
              <p className={styles.countPlays}>{data.songPlays}</p>
            </span>
            <span className={styles.actions}>
              <i className="fa-regular fa-bookmark"></i>
              <i className="fa-solid fa-share-nodes"></i>
            </span>
          </div>
        </div>
      </div>
    </section>
  )
}

There seems to be two issues that I have here. The first is that the data is not passing in to the 'Child component'.

The second issue seems more troubling and that is that the number of slides seems to be greater than the number of objects that are in the data api endpoint.

It should be a Dynamic number of slides matching data.length.

As far as I can tell, I am only pulling back the initial data once to populate the slides.

This is causing all of the slides to scrunch up to try and occupy the same amount of space that the data length would normally have used.

Any and all advice would be much appreciated after Doc surfing for a few days now.

It is possible that I am trying to tackle the problem the wrong way...if so please guide me so I can refactor.

Thanks and have a great day.

CodePudding user response:

First of all you forgot to pass the data to the SongCard component, do it like that:

// Add data prop here 
<SongCard key={data.songId} data={data} />

// And don't forget to destructure it in the component:
export function SongCard({ data }) {
  // ...
}

And second, do you even need this slides array? Just iterate over your data directly:

      {data.map((song) => (
        <SwiperSlide key={song.songId}>
          <SongCard data={song} />
        </SwiperSlide>
      ))}

I've made quick minimal reproduction on Codesandbox if you want to check working example:

Edit https://stackoverflow.com/questions/73338133

  • Related