@stripe/ui-extension-sdk
Version:
The suite of functionality available to UI extensions in Stripe apps
85 lines (84 loc) • 3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useStorage = useStorage;
const react_1 = require("react");
function getStorage() {
try {
return (
// Injected as a part of Sandbox initialisation by @sail/ext
globalThis.__memoryStorage ||
// Used solely for tests (in a real sandbox, access to web storage is blocked)
globalThis.sessionStorage);
}
catch (e) {
return null;
}
}
/**
* Hook for reading and writing shared data across different viewports of a Stripe App.
*
* Provides a way to synchronize state between all active instances
* (viewports) of your Stripe App within the same browser context. When the
* value is updated in one instance, all other instances in the same browser
* will reflect the change automatically. This is session-based storage that
* exists only while the app is running.
*
* Accepts a unique identifier for the storage item.
*
* Returns a tuple containing the current value from storage and a function to
* update the value in storage.
*
* Potential use cases:
* - Coordinating state between multiple viewports of your app
* - Avoiding redundant API calls by caching and sharing fetched data across viewports.
*
* Example:
* ```tsx
* // Share state across viewports
* const [currentTab, setCurrentTab] = useStorage('activeTab');
*
* // Update the shared value
* const handleTabChange = (tabName) => {
* setCurrentTab(tabName);
* };
*
* // All viewports will display the same tab
* return <Box>Active tab: {currentTab || 'home'}</Box>;
* ```
*
* Please note that
* - Values are limited to strings. For complex objects, please use JSON.stringify/parse.
* - Storage is not persistent between app sessions.
* - Changes won't synchronize between different browsers or devices.
*
* See: https://docs.stripe.com/stripe-apps/reference/extensions-sdk-api#useStorage
*/
function useStorage(key) {
const storage = getStorage();
const [value, setValueInternal] = (0, react_1.useState)(() => storage?.getItem(key));
const setItem = (0, react_1.useCallback)((val) => {
setValueInternal(val);
storage?.setItem(key, val);
}, [storage, key]);
(0, react_1.useEffect)(() => {
if (!storage) {
return;
}
function handleStorageEvent(event) {
const { storageArea, key: updatedKey, newValue, oldValue } = event;
if (storageArea !== storage) {
return;
}
if (updatedKey === key) {
setValueInternal(newValue);
}
// storage is cleared
if (updatedKey === null && oldValue === null && newValue === null) {
setValueInternal(null);
}
}
addEventListener('storage', handleStorageEvent);
return () => removeEventListener('storage', handleStorageEvent);
}, [storage, key]);
return [value ?? null, setItem];
}