davidhu2000/react-spinners

Spinner isn't not Spinning in Nextjs 14 (Server Side)

mahsanr44 opened this issue · 9 comments

I'm adding react-spinners in my Next.JS app but isn't spinning.
Here's my code:

import { ClimbingBoxLoader} from "react-spinners";
export default function Home() {
  return (
    <div>
<ClimbingBoxLoader 
  color="#36d7b7"
  loading
  speedMultiplier={2}
/>
      <MyComponent />
    </div>
  );
}

I have tested by using use client and it's working fine on the Client Side but I want it to be useful on the Server Side too.

i'll need to spent some time looking into how to handle the new server component paradigm. I think it's probably not working because the animation are created outside of the component

https://github.com/davidhu2000/react-spinners/blob/main/src/ClimbingBoxLoader.tsx#L7-L21

so maybe that code isn't executed after the code is sent to the client

Yeah, you're right, this could be the one of reasons.
Take your time and fix it.
Thanks

client-side animation stuff cannot be rendered on the server. They need to be marked as client component to work. Its not something that's fixable imo.

For now I just force all my loaders to be client components with a fallback for server side :

"use client"

import React, { useEffect, useState } from "react"
import { ClipLoader } from "react-spinners"

export const Loader = ({ size }: { size: number }) => {
  const [isClient, setIsClient] = useState(false)

  useEffect(() => {
    setIsClient(true)
  }, [])

  return (
    <React.Fragment>
      {isClient ? (
        <ClipLoader ... />
      ) : (
        <ServerSideSpinner ... />
      )}
    </React.Fragment>
  )
}

ServerSideSpinner is a regular spinner animated with tailwind.

Not sure this is a good approach, but it might help someone.

Don't do this, make a separate file, add "use client" tag on top, import the spinner and immediately export it as const or default (,ur choice) and import this spinner in your pages.

i haven't had time to work on this recently, but one potential approach would be add use client on top of each loader, and add a setState call for each animation. This ensures it will run on the client.

const [animation] = useState(createAnimation(...))

a quick test locally does seem to work, just need to update it all. Maybe hack on it in a coming weekend.

i thought maybe using next dynamic could do it, but the create Aniamtion still doesn't run on the client

const Loader = dynamic(() => import("react-spinners/ClimbingBoxLoader"), { ssr: false });
const [animation] = useState(createAnimation(...))

This will execute createAnimation on every render uselessly, I would advise using a callback

const [animation] = useState(() => createAnimation(...))