Next.js Discord

Discord Forum

Getting hydration error in client component (firebase/firestore)

Unanswered
XotEmBotZ posted this in #help-forum
Open in Discord
I am using firebase/firestore to get a list of strings and render bunch of components from that. The page is a server page but the component is client since it will require auth for firestore permissions. But I am getting hydration error. What is the way around ?

4 Replies

This is my component
'use client'
import { getChapters } from "@/firebase/firestore"
import Image from "next/image"
import Link from "next/link"

const ChapterCrousel = ({subjectCode}) => {
    const iconSrcLst = ['assets/svg/book-and-people-spring.svg', 'assets/svg/book-and-person-summer.svg', 'assets/svg/book-and-person-winter.svg',]
    const clipArtSize=200
    const crouselCards = () => {
        return getChapters(subjectCode).then(chapters => {
            return chapters.map(chapter => {
                return <>
                    <div className="carousel-item card bg-base-300 text-base-content w-fit shadow-xl max-w-56">
                        <figure className='p-3'>
                            <Image src={iconSrcLst[(Math.floor(Math.random() * iconSrcLst.length))]} width={clipArtSize} height={clipArtSize } alt={"Clipart logo"}/>
                        </figure>
                        <div className="card-body">
                            <h2 className="card-title capitalize">
                                {chapter.replaceAll("-"," ")}
                                <div className="badge badge-secondary">Imp!</div>
                            </h2>
                            <div className="card-actions justify-end">
                                <Link href={"/notes/"} className="badge badge-outline cursor-pointer">Notes</Link>
                                <Link href={"/questions/"} className="badge badge-outline cursor-pointer">Questions</Link>
                            </div>
                        </div>
                    </div></>
            })
        })
    }
  return (
      <div className="carousel gap-3 carousel-center rounded-box h-fit p-2 w-full">
          {crouselCards()}
      </div>
  )
}

export default ChapterCrousel
West African Crocodile
The hydration error occurs because the server and client renderings are not synchronized. This often happens when the client-side code fetches data asynchronously that isn't available during the initial server-side render. Here’s a way to fix it by using React state and effects to handle the asynchronous data fetch on the client side.

First, modify your component to fetch the data in a useEffect hook and manage the fetched data using state.
Here is the updated component:
'use client'
import { useEffect, useState } from "react";
import { getChapters } from "@/firebase/firestore";
import Image from "next/image";
import Link from "next/link";

const ChapterCrousel = ({ subjectCode }) => {
  const [chapters, setChapters] = useState([]);
  const iconSrcLst = ['assets/svg/book-and-people-spring.svg', 'assets/svg/book-and-person-summer.svg', 'assets/svg/book-and-person-winter.svg'];
  const clipArtSize = 200;

  useEffect(() => {
    getChapters(subjectCode).then(fetchedChapters => {
      setChapters(fetchedChapters);
    });
  }, [subjectCode]);

  const crouselCards = () => {
    return chapters.map((chapter, index) => {
      return (
        <div key={index} className="carousel-item card bg-base-300 text-base-content w-fit shadow-xl max-w-56">
          <figure className='p-3'>
            <Image src={iconSrcLst[(Math.floor(Math.random() * iconSrcLst.length))]} width={clipArtSize} height={clipArtSize} alt={"Clipart logo"} />
          </figure>
          <div className="card-body">
            <h2 className="card-title capitalize">
              {chapter.replaceAll("-", " ")}
              <div className="badge badge-secondary">Imp!</div>
            </h2>
            <div className="card-actions justify-end">
              <Link href={"/notes/"} className="badge badge-outline cursor-pointer">Notes</Link>
              <Link href={"/questions/"} className="badge badge-outline cursor-pointer">Questions</Link>
            </div>
          </div>
        </div>
      );
    });
  };

  return (
    <div className="carousel gap-3 carousel-center rounded-box h-fit p-2 w-full">
      {crouselCards()}
    </div>
  );
};

export default ChapterCrousel;