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.
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,
}
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;
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.