Mustafa Alfar
Mustafa Alfar

Reputation: 185

Cookie with static NextJS export return to initial value on page refresh

I am building a website, which has two languages, so I persist the selected language on cookie and retrieve it in the getInitialProps at _app file then pass it as a context API value. and I keep the cookie with sync to language state through the useEffect. the _app.js file look like this.

import React, { useState, useEffect } from 'react';
import nextCookie from 'next-cookies';
import * as Cookie from 'js-cookie';
import Head from 'next/head';
import { ThemeProvider } from 'emotion-theming';

import Layout from '../components/Common/Layout';
import GlobalStyle from '../components/GlobalStyle';
import { languageState, languageDispatch } from '../hooks/useLanguage';

function MyApp({ Component, pageProps, initialLanguage = 'ar' }) { 
    const [language, setLanguage] = useState(initialLanguage); 
    const changeLanuage = () => {
      setLanguage((prev) => (prev == 'en' ? 'ar' : 'en'));
    };

    useEffect(() => { 
      Cookie.set('language', language); 
    }, [language]);

    return (
    <languageDispatch.Provider value={changeLanuage}>
      <languageState.Provider value={language}>
        <ThemeProvider theme={theme}>
          <Layout>
            <Head>
              <link rel="shortcut icon" href="/svg/favicon.ico" />
            </Head>
            <Component {...pageProps} />
            <GlobalStyle rtl={rtl} />
          </Layout>
        </ThemeProvider>
      </languageState.Provider>
    </languageDispatch.Provider>
  );
} 
MyApp.getInitialProps = async ({ ctx }) => {
    const { language } = cookies(ctx); 
    return { initialLanguage: language }; 
};

in the development mode and deploying on now, it works perfectly with each page refresh. However, when I export it as static and deploy it on Netlify, with each refresh the language returns to its initial value ("ar").

Is there a better way to implement it, if no, what's wrong with the above implementation?

Upvotes: 1

Views: 4023

Answers (1)

Mustafa Alfar
Mustafa Alfar

Reputation: 185

After making some research, I figure out that when statically exporting NextJS's project while using getInitialProps or getStaticProps, NextJS will create the static HTML pages with initial-values - in this case, "ar" - so whenever you refresh the page the content will arrive with its initial-values, so in my previous approach, I was changing the cookie just at runtime. However, at the build-time, it was the initial-value "ar".

here's snippet code of the out/index.html

<script id="__NEXT_DATA__" type="application/json">
  {
    "props": { "initialLanguage": "ar" },
    "page": "/",
    "query": {},
    "buildId": "RmU4iA8jACDFdZr30Xqjo",
    "nextExport": true,
    "isFallback": false
  }
</script>

so I knew some approach to solve this issue, namely,

  1. upload NextJS as SSR, not SSG.

  2. duplicate pages per language, e.g. "/en", "/ar".

  3. save initial-value in localStorage and is useEffect change it, but you need to handle loading state while rendering the component and read the localStorage.

  4. use a third-party package.

So, the approach that I have gone through was to create two pages per language.

so the folder structure become somthing like that.

pages
 --[lang]
   --index.js
   --other.js
--index.js

and here's the pages/index.js

import Home from '../components/Home';
import Head from '../components/Common/Head';
import { useRouter } from 'next/router';
import getInitialLocale from '../locale/getInitialLocale';
import Spinner from '../components/Common/Spinner/Spinner';

const Index = () => {
  const router = useRouter();
  React.useEffect(() => {
    const href = `/${getInitialLocale()}`;
    router.push({ pathname: href });
  }, []);

  return (
    <div>
      <Head title="Home" />
      <h1 style={{ fontSize: '3rem' }}>Welcome to Here</h1>
    </div>
  );
};

export default Index;

If I did something wrong, or if you have better suggestions, comment here, please?

Upvotes: 0

Related Questions