-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add useLocalStorage hook #29
Conversation
Adds a ~~`useJSON`~~ `useStreamJSON` utility hook, to be used with large arrays of data, which normally would be too large for a command to load in memory directly. It can be used with either http(s) URLs, or `file:///` URLs. In either case, the hook will create a stream using the URL (either using `fetch` or `createReadStream`), and then use `stream-json` to stream through it. https://github.com/raycast/utils/assets/1155589/061e60b8-464f-45df-8a42-5172b1990377 - [x] Documentation - [x] Add support for arrays wrapped in objects, not just arrays - [x] Find a better name? 😅 => renamed to `useStreamJSON`
src/useLocalStorage.ts
Outdated
|
||
async function setValue(value: T) { | ||
try { | ||
await LocalStorage.setItem(key, JSON.stringify(value, replacer)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't you need to handle undefined
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean, that setItem
shouldn't be called if value
is undefined
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, but it should probably remove the value, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if the hook should be called useStoredState
to make the parallel with useCachedState
and useState
.
Additionally, I don't know if we really need removeValue
🤔
I feel like
|
Convey what? Is |
I forgot some words 😄 I meant, convey its meaning. |
src/useLocalStorage.ts
Outdated
} | ||
} | ||
|
||
return { value: value ?? initialValue, setValue, removeValue, isLoading }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to use the initialValue
here instead of passing it to the useCachedState
?
Thinking about it more, I think that when the cache is wiped (which can happen at any time) the initialValue will flicker even if there's something on the localStorage.
I'm wondering if we actually want the useCachedPromise
and the initialValue
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean useCachedPromise
instead of useCachedState
? The reason is to avoid having undefined
returned even if the user passed an initial value. What would you suggest instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes sorry.
The reason is to avoid having undefined returned even if the user passed an initial value.
I don't understand, useCachedPromise
should do that already.
But yeah I don't think caching the value and returning the initial value if there is no cache is what we want. I understand that it would allow you to get the previous value (maybe, sometimes) without having to wait but it will lead to flickers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand, useCachedPromise should do that already.
I don't know if that's intended or not, but even if I passed the initialData
option to useCachedPromise
, the value can still be undefined
for a brief moment. I'd expect it to never be undefined
if there's an initial value 🤔
So should we go with usePromise
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if that's intended or not, but even if I passed the initialData option to useCachedPromise, the value can still be undefined for a brief moment
Hum that's a bug then. Do you have a repro?
So should we go with usePromise then?
I'd say so yeah
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But, won't we get flickers as well with usePromise
? If an initial value is passed, the data will always load and we can get flickers as well if the value in the local storage is different than the initial one. Here's an example where the initial value is a list of three to-dos:
CleanShot.2024-04-18.at.12.08.27.mp4
Unless we should get rid of initialValue
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we actually want the useCachedPromise and the initialValue
That's what I said yeah, I don't think we need either
Also thinking about it, shouldn't we clear the local storage in the |
Hum I'm not too sure. It might be a temporary error or something, no? At worse, the value will get overwritten and that'd be it, no? |
src/useLocalStorage.ts
Outdated
async (storageKey: string) => { | ||
const item = await LocalStorage.getItem<string>(storageKey); | ||
|
||
return item ? (JSON.parse(item, reviver) as T) : initialValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall this be typeof item !=='undefined
? What happens if you store ""
?
|
||
async function toggleTodo(id: string) { | ||
const newTodos = todos?.map((todo) => (todo.id === id ? { ...todo, done: !todo.done } : todo)) ?? []; | ||
await setTodos(newTodos); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had another thought: I'm wondering if we could support a setTodos(todos => ...)
signature for the setter (similar to the setter of useState
). This could some async check 🤔
But I guess it can come in a follow up PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'd keep it simple for now. We can always iterate on it later since it won't be a breaking change.
This pull request introduces the
useLocalStorage
hook, which provides a convenient way to manage values stored in the local storage. The hook internally uses useCachedPromise
to cache the value and provide a loading state.Here's the signature:
And an example:
Screencast
CleanShot.2024-03-29.at.11.56.14.mp4