7 ways to persist state in frontend

Written by Bruno Nardini, Senior Staff Software Engineer at Pipefy.

Sometimes we want to persist (save) some user data without the complexity of having to send it to the backend. For example, a search filter, a table or list position, a selected tab, or any control or navigation data that is interesting for the users when they return to that page.

In this article I show 7 suggestions on how you can store data temporarily so that you can return it to the user when needed.

1 – Lifting State Up

Despite being an approach where the data is volatile, as it is not actually persisted, it is an option that is valid and very simple for many cases and is constantly ignored.

This approach works best on a Single-Page Application (SPA), but it also works on screens where the user spends a lot of time without leaving the screen, and consists of lifting the state to the highest level of the application hierarchy.

This technique is often used to share the state between different components of the hierarchy, but it is not just for that, we can use it to store the state in a component that will not be lost in a menu or screen navigation.

For example, the user is on Page 1 and selected Tab 2 from a menu, then he went to Page 2 and returned to Page 1 and will still find Tab 2 selected. This is possible by storing the position of the tab in a component above where the page routing is controlled.

2 – Session Storage

Session storage allows you to store key-value pairs in the browser’s storage, which can persist even after the browser is closed. You can use JavaScript to read and write data to session storage, which can be useful for storing small amounts of data such as user preferences or settings.

The Window.sessionStorage API is very simple and easy to use:

// Adds a value using a key
sessionStorage.setItem(‘myName’, ‘Nardini’);

// Retrieves the value according to its key
const name = sessionStorage.getItem(‘myName’);

// Removes a value according to the key

This information is registered in the browser and the keys and values are exclusive to your website’s domain, so there is no danger of key collisions with other websites. However, all the data from sessionStorage is available only while the page session is active, if the session ends the data will be discarded.

The page session may be handled differently depending on the browser, but for Google Chrome it is handled as follows:

  • The session is not shared between tabs, so each tab will have its own session, even if they are in the same domain. However, if you use the feature to duplicate the tab, it duplicates the session as well, but then continues to keep them independent.
  • The session ends when closing the tab.
  • The session persists when refreshing the page.

3 – Local Storage

Window.localStorage is an API similar to Session Storage, except that while localStorage data has no expiration time, it is not clear when the page session ends.

Usage is the same, just changes the name of the functions:

// Adds a value using a key
localStorage.setItem(‘myName’, ‘Nardini’);

// Retrieves the value according to its key
const name = localStorage.getItem(‘myName’);

// Removes a value according to the key

In Google Chrome, the data is shared between tabs of the same domain. The user can refresh the page, close the tab and the browser, turn off the machine and the state will still remain in the browser. The behavior is usually the same in other browsers, only changing the limit of the maximum amount of data that each one accepts.

It is worth remembering that Local Storage, despite being maintained over time, is only for temporary data that is of no importance if the user loses it. It is also important to be concerned about security, as this data is easily accessible.

Both Session and Local Storage are members of the Web Storage API.

4 – URL

The URL not only serves as the address of the pages, we can also define their state.

In the past, each change in the URL triggered a screen reload, but nowadays we are completely free to change the URL via JavaScript without this side effect, making it much more dynamic and conducive to saving any state on the page.

Below is an image with the name of the parts that make up a URL:

My suggestion is that you work with these three parts in this way:

  • The Path is used for navigation, but you don’t have to limit yourself to the page only, you can break the layout into subdivisions and use the Path itself to identify each one of them.
  • Use Parameters to record control values, such as search filters, for example, or for simpler navigation, such as the position of a tab.
  • The Hash is used as an anchor by the browser, you can use it to keep track of which section of the screen the user is on.

The benefits of using the URL are:

  • When updating the URL, you can replace or add to the history. If you add it to the history, when the user clicks the browser’s back button it will go back to the previous state, and so on, creating a more fluid way of browsing.
  • The state remains when the user refreshes the page, because the URL remains the same.
  • The user can save the URL in the bookmark and when he returns it will be in the same state as when he saved it.
  • If a user shares the URL with another user, they have also shared the state.

You can use this approach along with the others mentioned in this article, for example persisting state in URL and Local Storage, so you get the benefits of both approaches. Just be careful to keep the state consistent in both places.

5 – Server Side

The frontend is not restricted to the client side, currently there are several techniques that include server side processing, such as Server Side Rendering (SSR) for example. If this is your case, you get another range of options to store the state temporarily. For this purpose, it is possible to use an in-memory data store to persist this state for a while, like Redis and Memcached for example.

Do not overdo this architecture to not bring unnecessary complexity. All information coming from the server requires special attention to the caching strategy, so this will already bring all the complexity that makes this approach unfeasible in most cases, so only choose this path if it is simple and makes sense for the current architecture of your application.

6 – HTTP Cookies

An HTTP cookie (web cookie, browser cookie) is the oldest way to store data on the web, but unlike Web Storage which is client-only, cookies are sent with every request, so they can worsen performance (especially for mobile data connections).

If access is given (if the HttpOnly flag isn’t set by the server), it is possible to create new cookies via JavaScript using the Document.cookie API:

document.cookie = “yummy_cookie=choco”;
document.cookie = “tasty_cookie=strawberry”;
// logs “yummy_cookie=choco; tasty_cookie=strawberry”

Although the most common use of cookies is to track user login state, it is necessary to know and understand very well how it works to keep the whole flow safe, to avoid attacks like session hijacking for example.

7 – IndexedDB

If you have a need to store a significant amount of structured data on the client side, IndexDB is a good choice, its API uses indexes to enable high-performance searches of this data.

This feature is available in Web Workers, this allows operations to be done even if the user is offline. This makes it a good option for Progressive Web Apps (PWAs) and other offline-first applications.

However, using IndexedDB requires a good understanding of browser-based databases and asynchronous programming. And also has some limitations, such as a lack of support for complex transactions and queries, and restrictions on the size of individual records. Using IndexedDB can be a bit more complex than other state management solutions, but it provides a powerful way to store large amounts of data in a browser-based database.

Closing Thoughts

In a frontend project, persisting state is important to ensure that user data and preferences are saved and can be accessed across sessions, page refresh or just when switching pages. There are several ways to achieve this, including using local storage, cookies, session storage, state management libraries, and server-side storage solutions. 

Each of these methods has its own advantages and limitations, and the choice of which to use will depend on factors such as data size, security requirements, and application complexity. By understanding the available options and choosing the most appropriate approach for your specific project, you can effectively persist state and provide a better user experience for your users.

Similar Posts

Leave a Reply