Next.js Discord

Discord Forum

hydration issue

Unanswered
Shaurya posted this in #help-forum
Open in Discord
https://srcb.in/31gdFt4Hr6
I've made a loading screen, it works perfect as I want but I get an error:
Warning: Prop `style` did not match. Server: "animation-duration:0.7999999999999999s" Client: "animation-duration:0.4s"
    at div
    at div
    at div
    at Loading
what could I doto fix that issue?

30 Replies

can i see the code where you used animation-duration?
there I set the animation-duration to the div
ya what is line 30
i can't see
oh its in the link
yeah
return lines.map(line => line) sounds redundant
why not just return lines
what i meant by useState is
const [mounted, setMounted] = useState(false)

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

return ( mounted ? children : <></> )
but im not sure again
@alfon return lines.map(line => line) sounds redundant
oh, yea, did that, forgot it's already an array
this is the updated code with the mounted method: https://srcb.in/WTTuPtV127
it gets rid of the error. like it takes some time to mount and in that time the screen in blank and when it's mounted the loader is shown for very less time, I could increase the duration of the loader but the blank screen before the mount would be still there.
but I want the loading screen to show up immediately, what do I do to fix it?
the error is due to getUniqueRandomFromArr() i think, the random prerendered on the server is not the same as the random prerendered on the client
@joulev the error is due to getUniqueRandomFromArr() i think, the random prerendered on the server is not the same as the random prerendered on the client
hmm, what could I do for fixing it?
this is the function, gets a unique random element from an array
export function getUniqueRandomFromArr<T>(arr: T[]): T {
  const random = getRandomFromArr(arr)
  arr.splice(arr.indexOf(random), 1)
  return random
}
no need
@joulev no need
can you give me the docs on Server Component to pass data to Client Components or some tutorial, haven't ever used server components in nextjs and just tried many things but I did it wrong
"use server"

import { generateRange, getUniqueRandomFromArr } from "@/lib/utils/array"
import styles from "@/styles/utils/Loading.module.css"

export default async function Lines() {
  const numberOfLines = 5
  const min = 0.3
  const step = 0.1
  const max = min + step * numberOfLines
  const durations = generateRange(min, max, step)

  const lines = []

  for (let i = 0; i < numberOfLines; i++) {
    const duration = getUniqueRandomFromArr(durations)
    const formattedDuration = duration.toFixed(1)
    lines.push(
      <div
        key={i}
        className={styles.line}
        style={{ animationDuration: `${formattedDuration}s` }}
      />
    )
  }

  return <div className={styles.lines}>{lines}</div>
}
"use client"

import { useEffect } from "react"
import Lines from "@/lib/actions/utils/loading"
import styles from "@/styles/utils/Loading.module.css"

const numberOfLines = 5

export default function Loading() {
  useEffect(() => {
    const loader = document.getElementById("loader") as HTMLElement

    if (!loader) return

    setTimeout(() => {
      loader.style.opacity = "0"

      setTimeout(() => {
        loader.style.display = "none"
      }, 300)
    }, 100)
  }, [])

  return (
    <div id="loader" className={styles.loader}>
      <Lines />
    </div>
  )
}
export default function Loading() {
  const randomNumber = getRandomNumber();
  return <LoadingClient seed={randomNumber} />;
}

"use client";
export default function LoadingClient({ seed }) {
  const randomArray = getRandomArrayFromSeed(seed);
  return <div>...</div>;
}
@joulev ts export default function Loading() { const randomNumber = getRandomNumber(); return <LoadingClient seed={randomNumber} />; } ts "use client"; export default function LoadingClient({ seed }) { const randomArray = getRandomArrayFromSeed(seed); return <div>...</div>; }
didn't understand how would that actually work and how would I implement it in mine
I did this:
@/lib/actions/utils/loading:
"use client"

import { useEffect } from "react"
import { getUniqueRandomFromArr } from "@/lib/utils/array"
import styles from "@/styles/utils/Loading.module.css"

export default function Lines({ durations }: { durations: number[] }) {
  const numberOfLines = 5

  useEffect(() => {
    const loader = document.getElementById("loader")

    if (!loader) return

    setTimeout(() => {
      loader.style.opacity = "0"

      setTimeout(() => {
        loader.style.display = "none"
      }, 300)
    }, 100)
  }, [])

  function renderLines() {
    const lines = []

    for (let i = 0; i < numberOfLines; i++) {
      const duration = getUniqueRandomFromArr(durations)
      lines.push(<div key={i} className={styles.line} style={{ animationDuration: `${duration}s` }} />)
    }

    return lines
  }

  return (
    <div id="loader" className={styles.loader}>
      <div className={styles.lines}>{renderLines()}</div>
    </div>
  )
}
Loading.tsx:
import Lines from "@/lib/actions/utils/loading"
import { generateRange } from "@/lib/utils/array"
import styles from "@/styles/utils/Loading.module.css"

const numberOfLines = 5

export default function Loading() {
  const min = 0.3
  const step = 0.1
  const max = min + step * numberOfLines
  const durations = generateRange(min, max, step)

  return (
    <div id="loader" className={styles.loader}>
      <Lines durations={durations} />
    </div>
  )
}
@Shaurya didn't understand how would that actually work and how would I implement it in mine I did this: `@/lib/actions/utils/loading`: tsx "use client" import { useEffect } from "react" import { getUniqueRandomFromArr } from "@/lib/utils/array" import styles from "@/styles/utils/Loading.module.css" export default function Lines({ durations }: { durations: number[] }) { const numberOfLines = 5 useEffect(() => { const loader = document.getElementById("loader") if (!loader) return setTimeout(() => { loader.style.opacity = "0" setTimeout(() => { loader.style.display = "none" }, 300) }, 100) }, []) function renderLines() { const lines = [] for (let i = 0; i < numberOfLines; i++) { const duration = getUniqueRandomFromArr(durations) lines.push(<div key={i} className={styles.line} style={{ animationDuration: `${duration}s` }} />) } return lines } return ( <div id="loader" className={styles.loader}> <div className={styles.lines}>{renderLines()}</div> </div> ) } `Loading.tsx`: tsx import Lines from "@/lib/actions/utils/loading" import { generateRange } from "@/lib/utils/array" import styles from "@/styles/utils/Loading.module.css" const numberOfLines = 5 export default function Loading() { const min = 0.3 const step = 0.1 const max = min + step * numberOfLines const durations = generateRange(min, max, step) return ( <div id="loader" className={styles.loader}> <Lines durations={durations} /> </div> ) }
i need a minimal reproduction repository. impossible to debug unless i know what getUniqueRandomFromArr does
I just deployed it to vercel https://loader-self.vercel.app/ and in production the error doesn't come
but in dev environment why is that error coming?
i'm having a different problem elsewhere that requires my full attention, could you wait until later today
sure, no problem, the error only comes in the dev environment and not in the production environement and it works perfect, but that error on the console confused me because I don't see anything wrong
@Shaurya didn't understand how would that actually work and how would I implement it in mine I did this: `@/lib/actions/utils/loading`: tsx "use client" import { useEffect } from "react" import { getUniqueRandomFromArr } from "@/lib/utils/array" import styles from "@/styles/utils/Loading.module.css" export default function Lines({ durations }: { durations: number[] }) { const numberOfLines = 5 useEffect(() => { const loader = document.getElementById("loader") if (!loader) return setTimeout(() => { loader.style.opacity = "0" setTimeout(() => { loader.style.display = "none" }, 300) }, 100) }, []) function renderLines() { const lines = [] for (let i = 0; i < numberOfLines; i++) { const duration = getUniqueRandomFromArr(durations) lines.push(<div key={i} className={styles.line} style={{ animationDuration: `${duration}s` }} />) } return lines } return ( <div id="loader" className={styles.loader}> <div className={styles.lines}>{renderLines()}</div> </div> ) } `Loading.tsx`: tsx import Lines from "@/lib/actions/utils/loading" import { generateRange } from "@/lib/utils/array" import styles from "@/styles/utils/Loading.module.css" const numberOfLines = 5 export default function Loading() { const min = 0.3 const step = 0.1 const max = min + step * numberOfLines const durations = generateRange(min, max, step) return ( <div id="loader" className={styles.loader}> <Lines durations={durations} /> </div> ) }
make this Lines a server component and move useEffect to another client component
import { getUniqueRandomFromArr } from "@/lib/utils/array";
import styles from "@/styles/utils/Loading.module.css";
import AnimateLoader from "./animate-loader";

export default function Lines({ durations }: { durations: number[] }) {
  const numberOfLines = 5;

  function renderLines() {
    const lines = [];

    for (let i = 0; i < numberOfLines; i++) {
      const duration = getUniqueRandomFromArr(durations);
      lines.push(
        <div
          key={i}
          className={styles.line}
          style={{ animationDuration: `${duration}s` }}
        />
      );
    }

    return lines;
  }

  return (
    <div id="loader" className={styles.loader}>
      <div className={styles.lines}>{renderLines()}</div>
      <AnimateLoader />
    </div>
  );
}

"use client";

import { useEffect } from "react";

export default function AnimateLoader() {
  useEffect(() => {
    const loader = document.getElementById("loader");

    if (!loader) return;

    setTimeout(() => {
      loader.style.opacity = "0";

      setTimeout(() => {
        loader.style.display = "none";
      }, 300);
    }, 100);
  }, []);
  return null;
}