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

Written by sssaini | Published 2023/12/14
Tech Story Tags: javascript | storing-users-prefs | nextjs | react-hook | how-to-set-up-a-local-storage | how-to-use-a-react-hook | programming-tips | how-to-store-app-preferences

TLDROur 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.via the TL;DR App

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.

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.


Written by sssaini | Writes for saasbase.dev
Published by HackerNoon on 2023/12/14