-1

I want to use a headless CMO in my NextJs app (e.g. Sanity.io). The content is especially important for SEO. If I see it correctly, I can only receive the data on page-level via getStaticProps server-side to pre-render it that way (important for SEO).

If I now want to send the data from the page component to a deeply nested child, it's awkward via prop drilling. My first thought was to use React's Context API (see code).

However, I suspect that during the build the state of the Context API does not take over the values (The SEO text for example). So the pre-rendered page does not have the SEO content of the headless CMO.

Is there a way to send the values of the headless CMO to deeply nested children via getStaticProps without prop drilling? Or is the context API ok for this in terms of SEO / pre-render?

//pages/index.js

export default function Home({textFromGetStaticProps}) {
  const value = useAppContext();
  let {seotext, setSeotext} = value.content;

  console.log("The State is currently: " + seotext);
  console.log("The value of getStaticProps is currently:  " + textFromGetStaticProps);

//Can not set this in useEffect since only runs on ClientSide!
  setSeotext(() =>{
    console.log("---> setCount läuft");
    return textFromGetStaticProps;
  })

  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>
          The SEO Text is <a href="https://nextjs.org">{seotext}</a>
        </h1>
      </main>
    </div>
  )
}

//Fetch headless CMO Date via getStaticProps
export async function getStaticProps(context) {
  console.log("I am running Static Props");
  //API Fetch of headless CMO
  return {
    props: {textFromGetStaticProps: "SEO Text aus StaticProps"}, // will be passed to the page component as props
  }
}
//appContext.js
const AppContext = createContext();

export function AppWrapper({ children }) {
  const [seotext, setSeotext] = useState("SEO Text");
  const test = {seotext, setSeotext}
  console.log("I am Running AppContext: " + test);

  return (
    <AppContext.Provider value={{
      content: test,
    }}>
      {children}
    </AppContext.Provider>
  );
}

export function useAppContext() {
  return useContext(AppContext);
}
```
Manuel
  • 23
  • 4
  • As long as you set the initial value for your context based off what you return from `getStaticProps` it's fine to use React context to pass down the content. – juliomalves Oct 17 '22 at 18:54
  • That is correct @juliomalves. I have seen in the logs that the site is rendered with the initial values of the Context API. – Manuel Oct 21 '22 at 16:31

2 Answers2

0

There are a few ways to achieve this. The first that comes to mind would be to use something like the React Context API. However, you could also use something like Redux.

Here is an example using the Context API:

import React, { createContext, useContext, useState } from 'react';

const AppContext = createContext();

export function AppWrapper({ children }) {
  const [seotext, setSeotext] = useState("SEO Text");

  const test = {seotext, setSeotext}
  console.log("I am Running AppContext: " + test);

  return (
    <AppContext.Provider value={{
      content: test,
    }}>
      {children}
    </AppContext.Provider>
  );
}

export function useAppContext() {
  return useContext(AppContext);
}
Mohamed Elgazar
  • 778
  • 4
  • 9
  • That's the problem. Context API is not running (I guess) on the server side, so the content of the headless CMO from getStaticProps does not arrive at the deeply nestet children. Thus, no consideration is given to SEO. – Manuel Oct 16 '22 at 15:28
0

Future versions of Next.js will make this much easier but in the meantime you could try using SWR or React Query to fetch data for pre-rendering and then query inside nested components.

Joseph Race
  • 1,452
  • 14
  • 11
  • Oke too bad. I thought there were other "easier" ways. For me, the variant via useSWR is currently the best. Thanks for the tip. More Information is easy to find here: https://swr.vercel.app/docs/with-nextjs – Manuel Oct 21 '22 at 16:38