Hone logo
Hone
Problems

Implementing a useLocalStorage Hook in Vue with TypeScript

This challenge asks you to create a custom Vue Composition API hook, useLocalStorage, that provides a simple and type-safe way to interact with the browser's localStorage. This hook will handle reading, writing, and deleting data from localStorage while ensuring type safety and providing reactivity within your Vue components. It's a common pattern for persisting component state across page reloads.

Problem Description

You need to implement a useLocalStorage hook in Vue 3 using TypeScript. This hook should accept a key (string) and an initial value (of any type) as arguments. It should then:

  1. Read from localStorage: Attempt to read a value associated with the provided key from localStorage. If a value exists, parse it based on its type (string, number, boolean, or object/array - stringified). If no value exists, use the provided initial value.
  2. Provide a Reactive Reference: Return a ref containing the current value. This ref should be reactive, meaning changes to the value should trigger updates in any components using the hook.
  3. Provide Setter and Deleter Functions: Return an object containing two functions:
    • set(newValue: T): A function that accepts a new value of the same type as the initial value (T). This function should serialize the value to a string (if it's an object or array) and store it in localStorage associated with the provided key. It should also update the reactive ref with the new value.
    • delete(): A function that removes the key-value pair from localStorage and resets the reactive ref to its initial value.

Key Requirements:

  • Type Safety: The hook should be type-safe, ensuring that the set function only accepts values of the correct type.
  • Reactivity: Changes to the value should be reactive within Vue components.
  • Error Handling: Handle potential errors during localStorage access (e.g., localStorage being unavailable). In such cases, use the initial value.
  • Serialization/Deserialization: Correctly serialize objects and arrays to strings before storing them in localStorage and deserialize them when reading.

Expected Behavior:

  • The hook should correctly read and write values to localStorage.
  • Changes to the value in localStorage should be reflected in the reactive ref.
  • The delete function should remove the key-value pair from localStorage and reset the ref.
  • The hook should handle edge cases gracefully, such as localStorage being unavailable or invalid data in localStorage.

Examples

Example 1:

Input: useLocalStorage('myNumber', 0)
Output: { value: Ref<number>, set: (newValue: number) => void, delete: () => void }
Explanation:  Initializes a reactive ref with the value 0, stored under the key 'myNumber'.  If 'myNumber' exists in localStorage, it will be read and parsed as a number.

Example 2:

Input: useLocalStorage('myObject', { name: 'John', age: 30 })
Output: { value: Ref<{ name: string; age: number; }>, set: (newValue: { name: string; age: number; }) => void, delete: () => void }
Explanation: Initializes a reactive ref with the object { name: 'John', age: 30 }, stored under the key 'myObject'. If 'myObject' exists in localStorage, it will be read, parsed as JSON, and assigned to the ref.

Example 3: (Edge Case - localStorage unavailable)

Input: useLocalStorage('myString', 'Hello') when localStorage is disabled in the browser.
Output: { value: Ref<string>, set: (newValue: string) => void, delete: () => void }
Explanation: The hook should initialize the ref with the initial value 'Hello' and not attempt to access localStorage.

Constraints

  • The hook must be implemented using Vue 3's Composition API and TypeScript.
  • The initial value can be of any valid JavaScript type (string, number, boolean, object, array, etc.).
  • The hook should not introduce any external dependencies.
  • The serialization/deserialization process should be efficient enough for common use cases. Avoid complex or computationally expensive serialization methods.
  • The hook should be compatible with all modern browsers that support localStorage.

Notes

  • Consider using JSON.stringify and JSON.parse for serializing and deserializing objects and arrays.
  • Remember to handle potential errors when accessing localStorage.
  • Think about how to ensure that the reactive ref is updated correctly when the value in localStorage changes.
  • The delete function should reset the ref to the initial value, not null or undefined.
  • Type safety is crucial. Use generics to ensure that the set function only accepts values of the correct type.
Loading editor...
typescript