paint-brush
How We Store User Prefs in Local Storage Using Hooks in Next.jsby@sssaini
631 reads
631 reads

How We Store User Prefs in Local Storage Using Hooks in Next.js

by Sukhpal SainiDecember 14th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Our users wanted to store app preferences so that every time they use engyne.ai, they can start with the same settings applied. In our case, it was these 3 settings: Author, Publish Status, and Sorting Order. Ideally, once you select these, they should be selected permanently, even if you navigate away or log out.

Company Mentioned

Mention Thumbnail
featured image - How We Store User Prefs in Local Storage Using Hooks in Next.js
Sukhpal Saini HackerNoon profile picture

Our users wanted to store app preferences so that every time they use engyne.ai, they can start with the same settings applied.


In our case, it was these 3 settings: Author, Publish Status, and Sorting Order. Ideally, once you select these, they should be selected permanently, even if you navigate away or log out.


Engyne dashboard showing user pref settings

To do this, we decided to build a custom hook that would load and store user preferences from local storage.


Since the user can have multiple projects, the preferences should be saved per project.

Setting up the Local Storage

The name of the key would be: engyne-user-prefs-{{subdomain}}. The subdomain is the project name. For example - engyne-user-prefs-hackernoon.


This way, each key would have its own UserPrefsType. This type represents the settings that will be stored.


export type UserPrefsType = {
  sortType: string,
  publishingStatusFilter: string,
  authorFilter: string,
}


Creating the React Hook

Now that we know the key/value to store in the local storage, here’s how we create the React hook called useUserPrefs to both save and get value from the local storage.


Note that you can only store strings in the local storage, so all JSON has to be stringified when saving and parsed when retrieving.


We also specify a default value in case the project to get the user prefs is not specified.

//hooks/useUserPrefs.ts

import { useEffect, useState } from "react";
import { PostPublishStatus, PostSortType } from "/types";

export type UserPrefsType = {
  sortType: string,
  publishingStatusFilter: string,
  authorFilter: string,
}

const defaultUserPrefs: UserPrefsType = {
  sortType: PostSortType.NEWEST,
  publishingStatusFilter: PostPublishStatus.ALL,
  authorFilter: "",
}

const getLocalStorage = (key: string): UserPrefsType => {
  let currentValue;
  try {
    currentValue = JSON.parse(
      localStorage.getItem(key) || JSON.stringify(defaultUserPrefs)
    );
  } catch (error) {
    return defaultUserPrefs;
  }

  return currentValue;
}

const useUserPrefs = (subdomain: string) => {
  const key = `engyne-user-prefs-${subdomain}`

  const [value, setValue] = useState<UserPrefsType>(() => {
    if (!subdomain) return defaultUserPrefs;
    return getLocalStorage(key)
  });

  useEffect(() => {
    if (!subdomain) return;
    const currentValue = getLocalStorage(key);
    setValue(currentValue);
  }, [subdomain])

  useEffect(() => {
    if (!subdomain || !value) return;
    localStorage.setItem(key, JSON.stringify(value))
  }, [value])

  const updateUserPrefs = (userPref: Partial<UserPrefsType>) => {
    if (!subdomain) return;
    const currentValue = getLocalStorage(key);
    const updatedUserPrefs = { ...currentValue, ...userPref }
    setValue(updatedUserPrefs);
  }

  return { userPrefs: value, updateUserPrefs };
};

export default useUserPrefs;


Use the Hook in the Application

Now, we can import this hook into the application and get the saved author value from the local storage. First, we set up the hook to get the specified project’s user prefs, then we set the author value using theuserPrefs.authorFilter.


The updateUserPrefs is used whenever the user selects a different author name.


import {
  Select,
} from "@chakra-ui/react";

const subdomain = "hackernoon"

const { userPrefs, updateUserPrefs } = useUserPrefs(subdomain)
const authorsData = ["Author 1", "Author 2"]

// in component

<Select size="md" color="gray.600" width="unset" variant="unstyled" placeholder="Select author" onChange={(evt) => {
                  updateUserPrefs({ authorFilter: evt.target.value })
                }} value={userPrefs.authorFilter}>
                  {authorsData.map((author: any, i: number) => (
                    <option key={`author_${i}`} value={author.id}>
                      {author.name}
                    </option>
                  ))}
                </Select>


This is what the saved user prefs look like in local storage. Local Storage values for Engyne