Skip to content

How to Persist User Data with LocalStorage in Vue

Published: at 

Introduction

When developing apps, there’s often a need to store data. Consider a simple scenario where your application features a dark mode, and users want to save their preferred setting. Most users might be entirely content with dark mode, but occasionally, you’ll encounter someone who prefers otherwise. This situation raises the question: where should this preference be stored? One approach might be to use an API with a backend to store the setting. However, for configurations that only affect the client’s experience, it may be more practical to persist this data locally. LocalStorage is one method to achieve this. In this blog post, I’ll guide you through using LocalStorage in Vue. Furthermore, I’ll demonstrate various techniques to handle this data in an elegant and type-safe manner.

Understanding LocalStorage

LocalStorage is a web storage API that lets JavaScript websites store and access data directly in the browser indefinitely. This data remains saved across browser sessions. LocalStorage is straightforward, using a key-value store model where both the key and the value are strings.

Here’s how you can use LocalStorage:

Diagram that explains LocalStorage

Using LocalStorage for Dark Mode Settings

In Vue, you can use LocalStorage to save a user’s preference for dark mode in a component.

Picture that shows a button where user can toggle dark mode


<template>
  <button: ButtonHTMLAttributes & ReservedPropsbutton HTMLAttributes.class?: anyclass="dark-mode-toggle" @onClick?: ((payload: MouseEvent) => void) | undefinedclick="toggleDarkMode: () => voidtoggleDarkMode">
    {{ isDarkMode: anyisDarkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode' }}
    <span: HTMLAttributes & ReservedPropsspan HTMLAttributes.class?: anyclass="icon" v-html="isDarkMode: anyisDarkMode ? moonIcon: "<svg some svg </svg>"moonIcon : sunIcon: "<svg some svg </svg>"sunIcon" />
  </button: ButtonHTMLAttributes & ReservedPropsbutton>
</template>

<script setup lang="ts">
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
,
const computed: {
    <T>(getter: ComputedGetter<T>, debugOptions?: DebuggerOptions): ComputedRef<T>;
    <T, S = T>(options: WritableComputedOptions<T, S>, debugOptions?: DebuggerOptions): WritableComputedRef<T, S>;
}
computed
, const onMounted: CreateHook<any>onMounted } from 'vue'
const const isDarkMode: Ref<any, any>isDarkMode = ref<any>(value: any): Ref<any, any> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(var JSON: JSON
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON
.JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): any
Converts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is.
parse
(var localStorage: Storage
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/localStorage) A browser-compatible implementation of [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Data is stored unencrypted in the file specified by the `--localstorage-file` CLI flag. Any modification of this data outside of the Web Storage API is not supported. Enable this API with the `--experimental-webstorage` CLI flag.
@sincev22.4.0
localStorage
.Storage.getItem(key: string): string | null
Returns the current value associated with the given key, or null if the given key does not exist. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Storage/getItem)
getItem
('darkMode') ?? 'false'))
const
const styleProperties: ComputedRef<{
    '--background-color': string;
    '--text-color': string;
}>
styleProperties
=
computed<{
    '--background-color': string;
    '--text-color': string;
}>(getter: ComputedGetter<{
    '--background-color': string;
    '--text-color': string;
}>, debugOptions?: DebuggerOptions): ComputedRef<...> (+1 overload)
Takes a getter function and returns a readonly reactive ref object for the returned value from the getter. It can also take an object with get and set functions to create a writable ref object.
@example```js // Creating a readonly computed ref: const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error ``` ```js // Creating a writable computed ref: const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0 ```@paramgetter - Function that produces the next value.@paramdebugOptions - For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}.@see{@link https://vuejs.org/api/reactivity-core.html#computed}
computed
(() => ({
'--background-color': const isDarkMode: Ref<any, any>isDarkMode.Ref<any, any>.value: anyvalue ? '#333' : '#FFF', '--text-color': const isDarkMode: Ref<any, any>isDarkMode.Ref<any, any>.value: anyvalue ? '#FFF' : '#333' })) const const sunIcon: "<svg some svg </svg>"sunIcon = `<svg some svg </svg>` const const moonIcon: "<svg some svg </svg>"moonIcon = `<svg some svg </svg>` function function applyStyles(): voidapplyStyles () { for (const [const key: stringkey, const value: stringvalue] of var Object: ObjectConstructor
Provides functionality common to all JavaScript objects.
Object
.
ObjectConstructor.entries<string>(o: {
    [s: string]: string;
} | ArrayLike<string>): [string, string][] (+1 overload)
Returns an array of key/values of the enumerable own properties of an object
@paramo Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
entries
(
const styleProperties: ComputedRef<{
    '--background-color': string;
    '--text-color': string;
}>
styleProperties
.
ComputedRef<{ '--background-color': string; '--text-color': string; }>.value: {
    '--background-color': string;
    '--text-color': string;
}
value
)) {
var document: Document
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.documentElement: HTMLElement
Gets a reference to the root node of the document. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/documentElement)
documentElement
.ElementCSSInlineStyle.style: CSSStyleDeclaration
[MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement/style)
style
.CSSStyleDeclaration.setProperty(property: string, value: string | null, priority?: string): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/CSSStyleDeclaration/setProperty)
setProperty
(const key: stringkey, const value: stringvalue)
} } function function toggleDarkMode(): voidtoggleDarkMode () { const isDarkMode: Ref<any, any>isDarkMode.Ref<any, any>.value: anyvalue = !const isDarkMode: Ref<any, any>isDarkMode.Ref<any, any>.value: anyvalue var localStorage: Storage
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/localStorage) A browser-compatible implementation of [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Data is stored unencrypted in the file specified by the `--localstorage-file` CLI flag. Any modification of this data outside of the Web Storage API is not supported. Enable this API with the `--experimental-webstorage` CLI flag.
@sincev22.4.0
localStorage
.Storage.setItem(key: string, value: string): void
Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously. Throws a "QuotaExceededError" DOMException exception if the new value couldn't be set. (Setting could fail if, e.g., the user has disabled storage for the site, or if the quota has been exceeded.) Dispatches a storage event on Window objects holding an equivalent Storage object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Storage/setItem)
setItem
('darkMode', var JSON: JSON
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON
.JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
@paramvalue A JavaScript value, usually an object or array, to be converted.@paramreplacer A function that transforms the results.@paramspace Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
stringify
(const isDarkMode: Ref<any, any>isDarkMode.Ref<any, any>.value: anyvalue))
function applyStyles(): voidapplyStyles() } // On component mount, apply the stored or default styles function onMounted(hook: any, target?: ComponentInternalInstance | null): voidonMounted(function applyStyles(): voidapplyStyles) </script> <style scoped> .dark-mode-toggle { display: flex; align-items: center; justify-content: space-between; padding: 10px 20px; font-size: 16px; color: var(--text-color); background-color: var(--background-color); border: 1px solid var(--text-color); border-radius: 5px; cursor: pointer; } .icon { display: inline-block; margin-left: 10px; } :root { --background-color: #FFF; --text-color: #333; } body { background-color: var(--background-color); color: var(--text-color); transition: background-color 0.3s, color 0.3s; } </style>

Addressing Issues with Initial Implementation

In simple scenarios, the approach works well, but it faces several challenges in larger applications:

  1. Type Safety and Key Validation: Always check and handle data from LocalStorage to prevent errors.
  2. Decoupling from LocalStorage: Avoid direct LocalStorage interactions in your components. Instead, use a utility service or state management for better code maintenance and testing.
  3. Error Handling: Manage exceptions like browser restrictions or storage limits properly as LocalStorage operations can fail.
  4. Synchronization Across Components: Use event-driven communication or shared state to keep all components updated with changes.
  5. Serialization Constraints: LocalStorage stores data as strings. Serialization and deserialization can be tricky, especially with complex data types.

Solutions and Best Practices for LocalStorage

To overcome these challenges, consider these solutions:

// types/localStorageTypes.ts
export type 
type UserSettings = {
    name: string;
}
UserSettings
= {name: stringname: string}
export type
type LocalStorageValues = {
    darkMode: boolean;
    userSettings: UserSettings;
    lastLogin: Date;
}
LocalStorageValues
= {
darkMode: booleandarkMode: boolean, userSettings: UserSettingsuserSettings:
type UserSettings = {
    name: string;
}
UserSettings
,
lastLogin: DatelastLogin: Date, } export type type LocalStorageKeys = keyof LocalStorageValuesLocalStorageKeys = keyof
type LocalStorageValues = {
    darkMode: boolean;
    userSettings: UserSettings;
    lastLogin: Date;
}
LocalStorageValues
// utils/LocalStorageHandler.ts
// import { LocalStorageKeys, LocalStorageValues } from '@/types/localStorageTypes';

export class class LocalStorageHandlerLocalStorageHandler {
  static LocalStorageHandler.getItem<K extends LocalStorageKeys>(key: K): LocalStorageValues[K] | nullgetItem<function (type parameter) K in LocalStorageHandler.getItem<K extends LocalStorageKeys>(key: K): LocalStorageValues[K] | nullK extends type LocalStorageKeys = keyof LocalStorageValuesLocalStorageKeys>(
    key: K extends LocalStorageKeyskey: function (type parameter) K in LocalStorageHandler.getItem<K extends LocalStorageKeys>(key: K): LocalStorageValues[K] | nullK
  ): 
type LocalStorageValues = {
    darkMode: boolean;
    userSettings: UserSettings;
    lastLogin: Date;
}
LocalStorageValues
[function (type parameter) K in LocalStorageHandler.getItem<K extends LocalStorageKeys>(key: K): LocalStorageValues[K] | nullK] | null {
try { const const item: string | nullitem = var localStorage: Storage
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/localStorage) A browser-compatible implementation of [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Data is stored unencrypted in the file specified by the `--localstorage-file` CLI flag. Any modification of this data outside of the Web Storage API is not supported. Enable this API with the `--experimental-webstorage` CLI flag.
@sincev22.4.0
localStorage
.Storage.getItem(key: string): string | null
Returns the current value associated with the given key, or null if the given key does not exist. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Storage/getItem)
getItem
(key: keyof LocalStorageValueskey);
return const item: string | nullitem ? var JSON: JSON
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON
.JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): any
Converts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is.
parse
(const item: stringitem) as
type LocalStorageValues = {
    darkMode: boolean;
    userSettings: UserSettings;
    lastLogin: Date;
}
LocalStorageValues
[function (type parameter) K in LocalStorageHandler.getItem<K extends LocalStorageKeys>(key: K): LocalStorageValues[K] | nullK] : null;
} catch (function (local var) error: unknownerror) { var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stderr` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const code = 5; console.error('error #%d', code); // Prints: error #5, to stderr console.error('error', code); // Prints: error 5, to stderr ``` If formatting elements (e.g. `%d`) are not found in the first string then [`util.inspect()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilinspectobject-options) is called on each argument and the resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
error
(`Error retrieving item from localStorage: ${function (local var) error: unknownerror}`);
return null; } } static LocalStorageHandler.setItem<K extends LocalStorageKeys>(key: K, value: LocalStorageValues[K]): voidsetItem<function (type parameter) K in LocalStorageHandler.setItem<K extends LocalStorageKeys>(key: K, value: LocalStorageValues[K]): voidK extends type LocalStorageKeys = keyof LocalStorageValuesLocalStorageKeys>( key: K extends LocalStorageKeyskey: function (type parameter) K in LocalStorageHandler.setItem<K extends LocalStorageKeys>(key: K, value: LocalStorageValues[K]): voidK, value: LocalStorageValues[K]value:
type LocalStorageValues = {
    darkMode: boolean;
    userSettings: UserSettings;
    lastLogin: Date;
}
LocalStorageValues
[function (type parameter) K in LocalStorageHandler.setItem<K extends LocalStorageKeys>(key: K, value: LocalStorageValues[K]): voidK]
): void { try { const const item: stringitem = var JSON: JSON
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON
.JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
@paramvalue A JavaScript value, usually an object or array, to be converted.@paramreplacer A function that transforms the results.@paramspace Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
stringify
(value: boolean | UserSettings | Datevalue);
var localStorage: Storage
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/localStorage) A browser-compatible implementation of [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Data is stored unencrypted in the file specified by the `--localstorage-file` CLI flag. Any modification of this data outside of the Web Storage API is not supported. Enable this API with the `--experimental-webstorage` CLI flag.
@sincev22.4.0
localStorage
.Storage.setItem(key: string, value: string): void
Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously. Throws a "QuotaExceededError" DOMException exception if the new value couldn't be set. (Setting could fail if, e.g., the user has disabled storage for the site, or if the quota has been exceeded.) Dispatches a storage event on Window objects holding an equivalent Storage object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Storage/setItem)
setItem
(key: keyof LocalStorageValueskey, const item: stringitem);
} catch (function (local var) error: unknownerror) { var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stderr` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const code = 5; console.error('error #%d', code); // Prints: error #5, to stderr console.error('error', code); // Prints: error 5, to stderr ``` If formatting elements (e.g. `%d`) are not found in the first string then [`util.inspect()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilinspectobject-options) is called on each argument and the resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
error
(`Error setting item in localStorage: ${function (local var) error: unknownerror}`);
} } static LocalStorageHandler.removeItem(key: LocalStorageKeys): voidremoveItem(key: keyof LocalStorageValueskey: type LocalStorageKeys = keyof LocalStorageValuesLocalStorageKeys): void { var localStorage: Storage
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/localStorage) A browser-compatible implementation of [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Data is stored unencrypted in the file specified by the `--localstorage-file` CLI flag. Any modification of this data outside of the Web Storage API is not supported. Enable this API with the `--experimental-webstorage` CLI flag.
@sincev22.4.0
localStorage
.Storage.removeItem(key: string): void
Removes the key/value pair with the given key, if a key/value pair with the given key exists. Dispatches a storage event on Window objects holding an equivalent Storage object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Storage/removeItem)
removeItem
(key: keyof LocalStorageValueskey);
} static LocalStorageHandler.clear(): voidclear(): void { var localStorage: Storage
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/localStorage) A browser-compatible implementation of [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Data is stored unencrypted in the file specified by the `--localstorage-file` CLI flag. Any modification of this data outside of the Web Storage API is not supported. Enable this API with the `--experimental-webstorage` CLI flag.
@sincev22.4.0
localStorage
.Storage.clear(): void
Removes all key/value pairs, if there are any. Dispatches a storage event on Window objects holding an equivalent Storage object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Storage/clear)
clear
();
} }

// composables/useDarkMode.ts
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
, function watch<T, Immediate extends Readonly<boolean> = false>(source: WatchSource<T>, cb: WatchCallback<T, MaybeUndefined<T, Immediate>>, options?: WatchOptions<Immediate>): WatchHandle (+3 overloads)watch } from 'vue';
import { import LocalStorageHandlerLocalStorageHandler } from './LocalStorageHandler'; export function
function useDarkMode(): {
    isDarkMode: any;
}
useDarkMode
() {
const const isDarkMode: anyisDarkMode = ref<any>(value: any): any (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(import LocalStorageHandlerLocalStorageHandler.getItem('darkMode') ?? false);
watch<any, false>(sources: any, cb: WatchCallback<any, any>, options?: WatchOptions<false> | undefined): WatchHandle (+3 overloads)watch(const isDarkMode: anyisDarkMode, (newValue: anynewValue) => { import LocalStorageHandlerLocalStorageHandler.setItem('darkMode', newValue: anynewValue); }); return { isDarkMode: anyisDarkMode }; }

Diagram that shows how component and localStorage work together

You can check the full refactored example out here

Play with Vue on Vue Playground

Conclusion

This post explained the effective use of LocalStorage in Vue to manage user settings such as dark mode. We covered its basic operations, addressed common issues, and provided solutions to ensure robust and efficient application development. With these strategies, developers can create more responsive applications that effectively meet user needs.