Part 29: Understanding Local Storage and Hydration in Next.js
[Pages] Client-side Functionality

When building applications with Next.js, we often encounter scenarios that differ from traditional React apps. One such scenario is the challenge of using browser-specific features like Local Storage, in a framework that also executes code on the server. In this post, we'll explore how to handle such situations, focusing on the example of managing a "Dark Mode" setting with Local Storage.
The Challenge with Local Storage
Local Storage is a web API available only in the browser, allowing us to store key/value pairs. However, when running code on a server, such as with Node.js in Next.js, Local Storage is unavailable. This can lead to errors when trying to access it during server-side rendering.
Understanding the Error
When we attempt to read from localStorage during server-side execution, we encounter the error "localStorage is not defined." This happens because the server environment lacks the localStorage object, which is present in the browser.
Implementing a Solution
To resolve this issue, we need to ensure that our code only attempts to access localStorage when it runs in the browser. Here's how we can implement this in our ThemeSwitch component.
Safeguarding Local Storage Access
We'll modify our loadDarkMode function to check if localStorage is defined before attempting to use it. This ensures that our code only accesses Local Storage in the browser environment.
// components/ThemeSwitch.js
import { useState, useEffect } from 'react';
import DarkTheme from './DarkTheme';
function loadDarkMode() {
if (typeof localStorage === 'undefined') {
return false;
}
const value = localStorage.getItem('darkMode');
return (value === null) ? false : JSON.parse(value);
}
function ThemeSwitch() {
const [darkMode, setDarkMode] = useState(loadDarkMode);
const handleClick = () => {
localStorage.setItem('darkMode', JSON.stringify(!darkMode));
setDarkMode(!darkMode);
};
const text = darkMode ? 'Light Mode' : 'Dark Mode';
return (
<>
<button onClick={handleClick} suppressHydrationWarning>
{text}
</button>
<style jsx>{`
button {
background: none;
border: none;
color: inherit;
cursor: pointer;
}
`}</style>
{darkMode && <DarkTheme />}
</>
);
}
export default ThemeSwitch;Addressing Hydration Warnings
Another issue that arises is a hydration warning from React. This occurs because the server-rendered HTML may differ from the browser-rendered version due to the "darkMode" value being read from Local Storage in the browser.
React provides a property called suppressHydrationWarning to handle such discrepancies. By using this property on our button, we can suppress the warning, acknowledging that the difference is intentional and not an error.
Conclusion
Handling browser-specific features like Local Storage in a server-rendered framework such as Next.js requires careful consideration. By checking for the presence of these features and understanding the implications of server-side rendering, we can build robust applications. Suppressing hydration warnings, when appropriate, ensures a smoother development experience without unnecessary distractions.
This example illustrates the importance of adapting our approach when working in environments that blend server-side and client-side execution. By keeping these principles in mind, we can effectively leverage Next.js to create dynamic and user-friendly applications.
Last updated