Dimitri Borgers
Dimitri Borgers

Reputation: 278

How is data handled with getStaticProps when component uses it in useEffect()?

I have a page that uses the getStaticProps function. The function loads a list of objects that each hold three things: the title of a book, the author of a book, and then a list of characters in the book. The page then maps each of these objects to a component that puts them in a pretty pill.

The component takes the title and author and embeds it into its HTML code. However, the one complexity is the component also uses a useEffect() hook to randomly select 1 character within the character list provided as a prop and then displays them as part of the component HTML. Since it is useEffect(), this does not happen at build time. The reason I want it to occur when the user requests the page is that each user should see a different randomly selected character (i.e., although everything else on the page is the same for all users, I want the character to be randomly selected).

My question is, can getStaticProps work here? Does it build out the HTML as best it can and then when the user requests the page, the character list data is already provided? Or because it uses useEffect(), the component will have to re-request the data from the backend? I want to limit backend requests because the data is stored in AirTable and that only allows 5 calls per second.

index.jsx:

const Home = (props) => {
  return (
    <div className="flex min-h-screen">
      <main className="relative mx-5 mt-16">
          {props.response.map((bookData) => (
            <BookPill
              bookTitle={bookData['Book Title']}
              bookAuthor={bookData['Book Author']}
              bookCharacters={bookData['Characters']}
            />
          ))}
      </main>
    </div>
  )
}

export default Home

export async function getStaticProps(context) {
  try {
    const response = await getBookData()
    return {
      props: {
        response,
      },
      revalidate: 5,
    }
  } catch (error) {
    return {
      props: {
        err: 'Something went wrong 😕',
      },
    }
  }
}

BookPill.jsx:

const BookPill = ({
  bookTitle,
  bookAuthor,
  bookCharacters,
}: PropsType) => {
  const [randomCharacter, setRandomCharacter] = useState('')

   useEffect(() => {
     const random_character =
       bookCharacters[Math.floor(Math.random() * bookCharacters.length)]
     setRandomCharacter(random_character)
   }, [])

  return (
    <div className="my-2 grid grid-cols-1">
      <div className="px-5 text-center">
        <p className="mb-4">{bookTitle}</p>
        <p className="text-sm">{bookAuthor}</p>
      </div>
      <div className="flex items-center justify-center md:col-span-1">
        <div className="rounded-3xl">
          {randomCharacter}
        </div>
      </div>
    </div>
  )
}

export default BookPill

Upvotes: 1

Views: 268

Answers (1)

juliomalves
juliomalves

Reputation: 50308

To summarize what was discussed in the comments:

Because you're using getStaticProps with revalidate: 5, the data will only be fetched on the server, at most every 5 seconds. The data fetched inside getStaticProps is then passed to the HTML generated for the page - you can see the props returned from getStaticProps in the __NEXT_DATA__ script in your HTML.

When the page gets rendered on the browser, the useEffect is triggered and will use that data. No additional requests occur on the client-side.

Upvotes: 1

Related Questions