Use custom Hook (useLocalStorage)
To persist state we can use local storage to store the data. To implement it, we can create a custom hook called useLocalStorage and we can use it like a useState hook from react. To create that custom hook, we can follow this step:
1. Create a useLocalStorage.js file in our custom hook folder.
2. Add this code;
import React, { useState } from 'react';
export const useLocalStorage = (key, initialValue) => {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
if (typeof window === "undefined") {
return initialValue;
}
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
};
In this example, we define a useLocalStorage hook that takes a key and an initialValue as arguments. The key is used to identify the value in the local storage, and the initialValue is used as the default value if there is no value stored in the local storage for the given `key`.
The useLocalStorage hook returns an array with two values: the current stored value for the given key, and a function to update the stored value.
In the our component, we use the useLocalStorage hook to store and retrieve the value of our state. Whenever the user update the state, it will updates the stored value using the setter function returned by the useLocalStorage hook.
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
On this line of code, is used to handle any errors that may occur while setting the value in the local storage. There are several scenarios where an error might occur while setting the value in local storage, such as:
- The local storage is full and cannot store any more data.
- The user has disabled local storage for the current domain.
- There is a security restriction preventing the data from being stored in local storage.
To handle these errors in a more meaningful way, we can modify the catch block to throw an error with a user-friendly message, like this:
} catch (error) {
// swow a toast to inform the user
if (
error instanceof DOMException &&
error.code === DOMException.QUOTA_EXCEEDED_ERR
) {
console.log('Local storage is full');
} else if (
error instanceof DOMException &&
error.code === DOMException.SECURITY_ERR
) {
console.log(
'Local storage is disabled or Security restrictions prevent storage in local storage'
);
} else {
console.log(error);
}
}
For case 2 and 3 was rarely happening. But for case 1, we can handle it like clear the key in our local storage every time we done store the data to the database.
Reference:
Another option: Use Redux-Persist library:
Redux Persist is a library that helps to persist and rehydrate a Redux store across page reloads or even across sessions by storing the state in the browser's storage system (e.g. local storage, session storage, etc.). Here's an example of how to use Redux Persist to persist the state of a Redux store:
- Install the required dependencies:
npm install redux redux-persist
- Import the necessary modules:
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // defaults to localStorage for web
- Define the initial state and reducer for your store:
const initialState = {
counter: 0,
};
function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, counter: state.counter + 1 };
case 'DECREMENT':
return { ...state, counter: state.counter - 1 };
default:
return state;
}
}
- Define the persist configuration and wrap the reducer with
persistReducer:
const persistConfig = {
key: 'root',
storage,
};
const persistedReducer = persistReducer(persistConfig, reducer);
- Create the store using
createStoreand the persisted reducer:
const store = createStore(persistedReducer);
- Initialize the persistor using persistStore:
const persistor = persistStore(store);
- Wrap your app with
PersistGateto delay rendering until the persisted state is loaded:
import { PersistGate } from 'redux-persist/integration/react';
function App() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<YourApp />
</PersistGate>
</Provider>
);
}
Now, the state of our Redux store will be persisted across page reloads and across sessions using the browser's storage system. The PersistGate component will delay rendering until the persisted state is loaded, so we don't have to worry about rendering with an empty state. When the persisted state is loaded, it will replace the initial state of your store, so your app will continue with the last state before the reload.
**Reference: **https://www.npmjs.com/package/redux-persist
Storage option, Advantages and Disadvantages:
There are several storage options available for storing data locally in web applications. The most common options are:
1. Local Storage: Local storage is a browser-based storage mechanism that allows you to store key-value pairs in the browser. The data is stored in the browser's cache and persists even after the browser is closed. Local storage has a size limit of around 5-10 MB, depending on the browser.
Advantages of Local Storage:
- Easy to use, as it requires minimal setup and no server-side code.
- Can store data that persists between browser sessions.
- Can be accessed quickly and efficiently.
Disadvantages of Local Storage:
- Limited storage capacity, which may not be sufficient for storing large amounts of data.
- Data is only accessible within the browser, and cannot be shared between different devices or browsers.
- Data is vulnerable to attacks, such as cross-site scripting (XSS) attacks, that can allow an attacker to access or modify sensitive data.
2. Session Storage: Session storage is similar to local storage, but the data is only available during the current browser session. Once the browser is closed, the data is lost.
Advantages of Session Storage:
- Easy to use, as it requires minimal setup and no server-side code.
- Data is automatically cleared when the browser is closed, which can be useful for security and privacy reasons.
- Can be accessed quickly and efficiently.
Disadvantages of Session Storage:
- Limited storage capacity, which may not be sufficient for storing large amounts of data.
- Data is only accessible within the current browser session, and cannot be shared between different devices or browsers.
- Data is vulnerable to attacks, such as cross-site scripting (XSS) attacks, that can allow an attacker to access or modify sensitive data.
3. Cookies: Cookies are small text files that are stored in the browser's cache and can be used to store key-value pairs. Cookies can be set to expire after a certain period of time, or can be persistent.
Advantages of Cookies:
- Easy to use, as they require minimal setup and no server-side code.
- Can store data that persists between browser sessions.
- Can be used to store user preferences or login information.
Disadvantages of Cookies:
- Limited storage capacity, which may not be sufficient for storing large amounts of data.
- Data is only accessible within the browser, and cannot be shared between different devices or browsers.
- Data is vulnerable to attacks, such as cross-site scripting (XSS) attacks, that can allow an attacker to access or modify sensitive data.
- Cookies can be blocked or deleted by the user, which can result in data loss.
4. IndexedDB: IndexedDB is a browser-based database that allows you to store structured data in the browser. It has a larger storage capacity than local storage and session storage, and can be used to store more complex data structures.
Advantages of IndexedDB:
- Larger storage capacity than local storage and session storage.
- Can store structured data, making it more flexible than key-value stores.
- Can be used to store data that persists between browser sessions.
- Data is stored separately from the browser cache, providing better security and privacy.
Disadvantages of IndexedDB:
- More complex to use than local storage and session storage.
- IndexedDB is not supported by all browsers, which may limit its use in some applications.
- Data is vulnerable to attacks, such as cross-site scripting (XSS) attacks, that can allow an attacker to access or modify sensitive data.
The choice of storage mechanism will depend on the specific needs of your application. If you only need to store small amounts of data, local storage or session storage may be sufficient. If you need to store more complex data structures or larger amounts of data, IndexedDB may be a better
5. Redux: Redux is a state management library for JavaScript applications, and it can be used to store data locally in your web application. Redux works by maintaining a global state object, which can be updated by dispatching actions. Components can then subscribe to changes in the state and update their views accordingly.
Advantages of using Redux for local data storage:
- Redux provides a centralized store for managing application state, which can make it easier to manage complex data structures and keep the data in sync across the application.
- Redux provides a standardized way to update the state, making it easier to debug and maintain the code.
- The Redux store can be persisted using tools like Redux Persist or Redux Offline, allowing the data to persist even when the browser is closed or the user navigates away from the page.
- Redux can be used with other libraries and frameworks, making it a flexible solution that can be adapted to different application architectures.
Disadvantages of using Redux for local data storage:
- Setting up Redux can require additional setup and configuration compared to simpler storage mechanisms like local storage or session storage.
- Redux may not be necessary for simpler applications that only need to store small amounts of data locally.
- Redux may be overkill for applications that do not require complex state management.
In summary, Redux can be a powerful tool for managing local data in your web application, especially for larger or more complex applications. However, it may not be necessary or appropriate for all applications, and simpler storage mechanisms like local storage or session storage may be more appropriate in some cases.