How to persist data and access them on both client and server side in Next.js
Tags: javascript, react, nextjs
Published: 2021-02-11 13:52:56

Suppose you have data like `theme` and `locale`and you want to get their value as immediate as your Next.js app starts, be it client or server side. You obvious need a storage that can be accessed both client and server side, that storage is `Cookies` of coarse, but how?

Here is how I do it:

After you have successfully created your Next.js app, create a custom `_app.js` file, this is the file where our logic will be.

**Scenario**: When user initially opens the app or refreshes, it does server side rendering, I want to get the previous theme they selected before rendering the default theme then changing it, that is disturbing.

**Logic**: When user selects `theme`, lets say `light`, I change the current theme to what he selected and store its value to `Cookie storage` when user opens the app next time or refreshes it, I will grab that cookie during server side rendering and pass it as props to the app hence rendering the previous theme they selected.

**Note**: I use `Material UI` for styling and theming and `js-cookie` for cookies, you can use any, the aim is just to understand how I do it.

## _app.js
```javascript
import React from 'react';
import PropTypes from 'prop-types';
import { setCookie, getCookie } from '../libs/cookie';
import { darktheme, lighttheme } from '../libs/themes';
import { ThemeProvider } from '@material-ui/core/styles';
// Context API
import { ThemeContext } from '../context';

const App = ({ Component, pageProps, previousTheme }) => {
  const [theme, setTheme] = React.useState(previousTheme);

  const toggleTheme = async () => {
    if (theme === 'light') {
      setTheme('dark');
      setCookie('theme', 'dark');
    } else {
      setTheme('light');
      setCookie('theme', 'light');
    }
  };

  return (
    <React.Fragment>
      <ThemeContext.Provider value={theme} >
        <ThemeContext.Consumer>
          {
            value =>
              <ThemeProvider theme={value === 'dark' ? darktheme : lighttheme} >
                <Component toggleTheme={toggleTheme} {...pageProps} />
              </ThemeProvider>
          }
        </ThemeContext.Consumer>
      </ThemeContext.Provider>
    </React.Fragment>
  );
};

App.propTypes = {
  Component: PropTypes.elementType.isRequired,
  pageProps: PropTypes.object.isRequired
};

App.getInitialProps = async ({ Component, ctx }) => {
  let pageProps = {};
  let previousTheme = null;
  if (Component.getInitialProps) {
    pageProps = await Component.getInitialProps(ctx);
  }
  if (ctx.req) {
    previousTheme = await getCookie('theme', ctx.req.headers.cookie);
  }
  return {
    pageProps,
    previousTheme
  };
};

export default App;
```
I have `ThemeContext` to store theme state, `setCookie`, `getCookie` functions imported and `toggleTheme` function.

`getIntitialprops` is where the app starts, I check if it is server side rendered I get the cookie value using `getCookie` function and pass it as props to the app. `toggleTheme` is prop drilled to Component so that it can be accessed anywhere inside the app, this function updates the `currentTheme` state which in turn updates the `ThemeContext` and store the selected theme value to cookie using `setCookie` function.

## ThemeContext
```javascript
import { createContext } from 'react';

const ThemeContext = createContext();
export {
  ThemeContext
};
```

## libs/cookie.js
```javascript
const Cookies = require('js-cookie');

module.exports = {
  getCookie: async (cookiename, cookiestring) => {
    var name = cookiename + '=';
    var decodedCookie = decodeURIComponent(cookiestring);
    var ca = decodedCookie.split(';');
    for (var i = 0; i < ca.length; i++) {
      var c = ca[i];
      while (c.charAt(0) === ' ') {
        c = c.substring(1);
      }
      if (c.indexOf(name) === 0) {
        return c.substring(name.length, c.length);
      }
    }
    return '';
  },
  setCookie: (cookiename, cookievalue) => {
    Cookies.set(cookiename, cookievalue, { expires: 365 });
  }
};
```

You can add more data like `locale`, `jwt`, `sessionKey` whatever that you need to access on initial start or refresh or your Next.js app and get/process it at `getInitialprops`.

###Happy Hacking!