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
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
import { createContext } from 'react';
const ThemeContext = createContext();
export {
ThemeContext
};
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 });
}
};
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
.
Top comments (0)