简体   繁体   中英

Next.js + SSR not updating the Context API

We have a simple setup involving a Context API provider wrapping the _app.tsx page. The flow we're trying to implement is:

  1. On a page we collect some data from an API by using getServerSideProps
  2. We send the data to the page through the props
  3. We update the context from the page (the context provider is wrapping the _app.tsx as mentioned above)
  4. The context is updated and all the children components can access the data in it

So we have a pretty standard setup that works correctly on the client side. The problem is that the updated context values are not being used to SSR the pages.

Context API

const ContextValue = createContext();
const ContextUpdate = createContext();

export const ContextProvider = ({children}) => {
  const [context, setContext] = useState({});
  
  return <ContextValue.Provider value={context}>
    <ContextUpdate.Provider value={setContext}>
      {children}
    </ContextValue.Provider>
  </ContextUpdate.Provider>
}

export const useContextValue = () => {
  const context = useContext(ContextValue);
  return context;
}

export const useContextUpdate = () => {
  const update = useContext(ContextUpdate);
  return update;
}

Then we have on _app.jsx :

...
return <ContextProvider>
  <ContextApiConsumingComponent />
  <Component {...pageProps} />
</Context>

And in any page, if we can update the context by using the hook provided above. For example:

export function Index({customData, isSSR}) {
  const update = useContextUpdate();

  if(isSSR) {
    update({customData})
  }
  return (
    <div>...</div>
  );
}

export async function getServerSideProps(context) {
  ...

  return {
      props: { customData , isSSR}
  };
};

And we can consume the context in our ContextApiConsumingComponent :

export function ContextApiConsumingComponent() {
  const context = useContextValue()

  return <pre>{JSON.stringify(context?.customData ?? {})}</pre>
}

The (very simplified) code above works fine on the client. But during the SSR, if we inspect the HTML sent to the browser by the server, we'll notice that the <pre></pre> tags are empty even though the context values are correctly sent to the browser in the __NEXT_DATA__ script section (they are precisely filled with the data on the browser after the app is loaded).

I've put together a GitHub repo with a minimum reproduction too.

Am I missing something?

As far as I understand, React doesn't wait for asynchronous actions to be performed during the SSR. Whereas setState is an asynchronous operation.

If you want it to be rendered during SSR, you need to provide an initialValue for useState hook.

export const ContextProvider = ({children, customData}) => {
  const [context, setContext] = useState(customData);
  
  // ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM