Persistent Storage

You can access Local Storage and Session Storage with the @applicaster/zapp-react-native-bridge package. these APIs are backed by native implementation on the native platforms, and the browser's storage API on the web based platforms.

Key principles

Local Storage and Session Storage expose similar APIs. With both, you can set a value for a key, or get a value for a key. You can use a namespace in these operations to make sure you don't have name collision with other plugins, since the storage modules are shared within the app. Local Storage will persist values even if the app is killed and restarted, whereas Session Storage will only persist as long as the app is not reinitialized.

info

While these APIs are available on all platforms, be sure to thoroughly test your feature on all devices, and be aware that limitations can apply dependening on the devices. For instance, TV devices (Apple TV, Samsung, LG) have very limited storage capabilities, which can prevent some features relying heavily on local / session storage to function properly

API

LocalStorage

import { localStorage } from "@applicaster/zapp-react-native-brisge/ZappStorage/LocalStorage";
  • localStorage.getItem: (key: string, namespace?: string): Promise<any> retrieves a value from local storage

  • localStorage.setItem: (key: string, value: any, namespace?: string): Promise<boolean> sets a value in local storage. Returns a promise with a boolean flag indicating the success of the operation

  • localStorage.removeItem(key: string, namespace?: string): Promise<boolean> removes a key from local storage. Returns a promise with a boolean flag indicating the success of the operation

  • localStorage.getAllItems(namespace?: string): Promise<Object<string, any>> Gets all items in a given namespace. if no namespace is provided, will return the values in the applicaster namespace

  • localStorage.setKeychainItem(key: string, value: any, namespace?: string) Will set a value in the keychain storage. If no namespace is provided, will use the app's bundle identifier as namespace

  • localStorage.getKeychainItem(key: string, namespace?: string): Promise<any> Gets an item from keychain storage. if no namespace is provided, will use the app's bundle identifier as namespace

  • removeKeychainItem(key: string, namespace?: string) Removes an item from keychain storage. if no namespace is provided, will use the app's bundle identifier as namespace

  • addListener(options: {key?: string, namespace?: string}, listener: (options: {key: string, value: any, namespace: string}) => void): () => void Registers a listener which will be invoked when a key is changed in a namespace. the first argument is an object defining the key and namespace to listen to. If no key is provided, all key change in the namespace will invoke the listener. If no namespace is provided, the listener will be invoked on changes in the default namespace applicaster.v2. The listener is invoked with the key, the namespace and the new value. A null value means the key has been removed. This function returns a function to remove the listener (see example usage below)

info

The listener can only be used to listen for changes on non-secure item. Items stored in secure storage will not invoke the listeners

SessionStorage

import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
  • sessionStorage.getItem: (key: string, namespace?: string): Promise<any> retrieves a value from session storage

  • sessionStorage.setItem: (key: string, value: any, namespace?: string): Promise<boolean> sets a value in session storage. Returns a promise with a boolean flag indicating the success of the operation

  • sessionStorage.removeItem(key: string, namespace?: string): Promise<boolean> removes a key from session storage. Returns a promise with a boolean flag indicating the success of the operation

  • sessionStorage.getAllItems(namespace?: string): Promise<Object<string, any>> Gets all items in a given namespace. if no namespace is provided, will return the values in the applicaster namespace

  • addListener(options: {key?: string, namespace?: string}, listener: (options: {key: string, value: any, namespace: string}) => void): () => void Registers a listener which will be invoked when a key is changed in a namespace. the first argument is an object defining the key and namespace to listen to. If no key is provided, all key change in the namespace will invoke the listener. If no namespace is provided, the listener will be invoked on changes in the default namespace applicaster.v2. The listener is invoked with the key, the namespace and the new value. A null value means the key has been removed. This function returns a function to remove the listener (see example usage below)

Example

The example below shows only localStorage, but the sessionStorage API is essentially the same. Imagine a component which needs to set a property in storage when it mounts, and then check to see if there is a login token defined in storage to know if it should render a content screen or a login screen. We'd need to get the initial value of the token, and then listen for changes to show the login screen if the token is removed by another plugin or another screen in the app

import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
type Props = {
loginKey: string;
loginNamespace: string;
propToStore: any;
};
const pluginNamespace = "MyPluginNamespace";
const storageKey = "storageKey";
function MyComponent(props) {
// getting props
const { loginKey, loginNamespace, propToStore } = props;
// setting initial component states
const [token, setToken] = useState<string>(null);
const [keyStored, setKeyStored] = useState<boolean>(false);
// async function called on mount to retrieve the token
const getInitialTokenValue = async () => {
const token = await localStorage.getItem(loginKey, loginNamespace);
if (token) setToken(token);
};
// async function called on mount to store a value in storage
const setSorageValue = async () => {
const result = await localStorage.setItem(
storageKey,
propToStore,
pluginNamespace
);
if (result) setKeyStored(true);
};
// handler for key change. When the requested key in the request namespace is modified
// or removed, this handler will be invoked
const handleTokenChange = useCallback(async ({ key, namespace, value }) => {
console.log(`item ${namespace}.${key} was set to ${value}`);
setToken(value);
}, []);
// let's call these functions in useEffect, and add the listener
useEffect(() => {
getInitialTokenValue();
setStorageValue();
const removeListener = localStorage.addListener(
{ key: loginKey, namespace: loginNamespace },
handleTokenChange
);
// use the returned function from the `addListener` call
// to remove the listener when the component unmounts
return removeListener;
}, []);
const isLoggedIn = !!token && keyStored;
return isLoggedIn ? <ContentScreen token={token} /> : <LoginScreen />;
}