DEV Community

Raphael Chaula
Raphael Chaula

Posted on

How to persist data and access them on both client and server side in Next.js

Suppose you have data like theme and localeand 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

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;
Enter fullscreen mode Exit fullscreen mode

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

import { createContext } from 'react';

const ThemeContext = createContext();
export {
  ThemeContext
};
Enter fullscreen mode Exit fullscreen mode

libs/cookie.js

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 });
  }
};
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)