Description
Summary: A hook to simplify the creation and management of object dictionaries in LocalStorage, with a simple interface for CRUD operations. This would be useful for storing objects that populate List and Grid views, for example.
Details: This hook would create a LocalStorage entry containing a dictionary of objects as a JSON string, and it would provide easy access to methods for accessing, removing, and updating objects, as well as for performing object key migrations and batch-adding of new keys. A cached option could be provided.
Quite a few extensions store objects in this way and would benefit from a dedicated implementation, especially one that supports future development by providing methods for migrations (since the need/want to rename or delete keys is often unforeseen). Moreover, a standard implementation would allow additional features going forward, e.g. an option to use a JSON file in the extension's support directory rather than in LocalStorage, with minimal changes in extensions' code.
I'd be happy to work on this if there's support for it.
Proposed Interface:
interface LocalObjectStore<T> {
allObjects: () => T[];
// Add an object to the store, return the UUID for the object
addObject: (object: T) => string;
removeObject: (object: T) => void;
getObject: (id: string) => T | undefined;
setObject: (id: string, object: T) => void;
updateObject(id: string, updateFunction: (oldObject: T) => T): void;
removeObject: (id: string) => void;
clear: () => void;
// Rename a key within each obje
7505
ct in the store, preserving the value
renameKey: (oldKey: string, newKey: string) => void;
// Add a key to each object in the store, using the provided function to generate the value
addKey: (key: string, valueFunction: (object: T) => any) => void;
// Delete a key from each object in the store
deleteKey: (key: string) => void;
}
Example:
import { Action, ActionPanel, Grid } from "@raycast/api";
import { useObjectStore } from '@raycast/utils';
interface EmojiItem {
name: string;
emoji: string;
description: string;
}
export default function Command() {
// Creates the store if it doesn't exist, or returns the existing store
const emojiStore = useObjectStore<EmojiItem>('emoji-items');
useEffect(() => {
emojiStore.addObject({
name: 'Smile',
emoji: '😀',
description: 'A happy face',
});
}, []);
// Loads items once upon first render, updates when items are added/removed/modified
const emojiItems = emojiStore.allObjects();
return(
<Grid>
{emojiItems.map((item) => (
<Grid.Item
key={item.id} // Auto-generated UUID
title={item.name}
subtitle={item.description}
content={item.emoji}
actions={
<ActionPanel>
<Action
title="Remove"
onAction={() => emojiStore.removeObject(item.id)}
/>
</ActionPanel>
}
/>
))}
</Grid>
);
}