Skip to content

Commit

Permalink
docs(persist-web-storage): update persist-web-storage docs and example
Browse files Browse the repository at this point in the history
  • Loading branch information
osovv committed Feb 4, 2025
1 parent ead4d23 commit fff6d15
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 84 deletions.
50 changes: 20 additions & 30 deletions docs/src/content/docs/package/persist-web-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ The main goal of this adapter is to synchronize atom between tabs without pollut
import { atom } from '@reatom/framework'
import { withBroadcastChannel } from '@reatom/persist-web-storage'

export const isAuthedAtom = atom('', 'isAuthedAtom').pipe(
withBroadcastChannel('isAuthedAtom'),
)
export const isAuthedAtom = atom('', 'isAuthedAtom').pipe(withBroadcastChannel('isAuthedAtom'))
```

You can also give an instance of `BroadcastChannel`
Expand All @@ -68,10 +66,7 @@ myChannel.onmessage((event) => {

const withMyBroadcastChannel = reatomPersistBroadcastChannel(myChannel)


export const isAuthedAtom = atom('', 'isAuthedAtom').pipe(
withMyBroadcastChannel('isAuthedAtom'),
)
export const isAuthedAtom = atom('', 'isAuthedAtom').pipe(withMyBroadcastChannel('isAuthedAtom'))
```

### withIndexedDb
Expand All @@ -84,10 +79,9 @@ The main goal of this adapter is to persist atom's state to IndexedDB. `withInde
import { reatomResource, withCache } from '@reatom/framework'
import { withIndexedDb } from '@reatom/persist-web-storage'

export const listResource = reatomResource(
async (ctx) => api.getList(ctx.spy(pageAtom)),
'listResource',
).pipe(withCache({ withPersist: withIndexedDb }))
export const listResource = reatomResource(async (ctx) => api.getList(ctx.spy(pageAtom)), 'listResource').pipe(
withCache({ withPersist: withIndexedDb }),
)
```

You can also specify a custom database name and a custom `BroadcastChannel' that will be used to synchronize the data in real time.
Expand All @@ -96,35 +90,31 @@ You can also specify a custom database name and a custom `BroadcastChannel' that
import { reatomResource, withCache } from '@reatom/framework'
import { withIndexedDb } from '@reatom/persist-web-storage'

export const listResource = reatomResource(
async (ctx) => api.getList(ctx.spy(pageAtom)),
'listResource',
).pipe(withIndexedDb({ key: 'hugeListAtom', dbName: 'myCustomDb', channel }))
export const listResource = reatomResource(async (ctx) => api.getList(ctx.spy(pageAtom)), 'listResource').pipe(
withIndexedDb({ key: 'hugeListAtom', dbName: 'myCustomDb', channel }),
)
```

If you want to avoid flickering, all you have to do is add a small delay after the atom is connected. Subscribe / spy the data atom, wait the ready atom and then use the actual data.
If you want to avoid flickering, all you have to do is add `withIndexedDb.init(ctx)` at the top-level (before the application mounts).

> [example](https://github.com/artalar/reatom/blob/v3/examples/react-persist-web/src/app.tsx)
```ts
import { reatomResource, withCache, onConnect, sleep } from '@reatom/framework'
import { withIndexedDb } from '@reatom/persist-web-storage'

export const listResource = reatomResource(
async (ctx) => api.getList(ctx.spy(pageAtom)),
'listResource',
).pipe(withIndexedDb({ key: 'hugeListAtom', dbName: 'myCustomDb', channel }))
const isListReadyAtom = atom(false, 'isListReadyAtom')
onConnect(listResource, async (ctx) => {
await ctx.schedule(() => new Promise((r) => requestIdleCallback(r)))
isListReadyAtom(ctx, true)
return () => isListReadyAtom(ctx, false)
})
export const listResource = reatomResource(async (ctx) => api.getList(ctx.spy(pageAtom)), 'listResource').pipe(
withIndexedDb({ key: 'hugeListAtom', dbName: 'myCustomDb', channel }),
)

await withIndexedDb.init(ctx):

ctx.spy(listResource) // will return the actual value, without flcikering
```

### withCookie

Synchronizes atom state to the `document.cookie` with a given name.
Synchronizes atom state to the `document.cookie` with a given name.

When using `withCookie`, the first argument it takes is an options object that allows you to configure various aspects of cookie behavior.

Expand All @@ -141,9 +131,9 @@ interface CookieAttributes {
sameSite?: 'strict' | 'lax' | 'none'
}

export const tokenAtom = atom("", "tokenAtom").pipe(
export const tokenAtom = atom('', 'tokenAtom').pipe(
withCookie({
maxAge: 3600, // 1 hour
})("token"),
);
})('token'),
)
```
64 changes: 16 additions & 48 deletions examples/react-persist-web/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,53 @@
import { atom, onConnect } from '@reatom/framework'
import {
withLocalStorage,
withBroadcastChannel,
withSessionStorage,
withIndexedDb,
} from '@reatom/persist-web-storage'
import { atom } from '@reatom/framework'
import { withLocalStorage, withBroadcastChannel, withSessionStorage, withIndexedDb } from '@reatom/persist-web-storage'
import { useAtom } from '@reatom/npm-react'

const inputWithLocalStorageAtom = atom('', 'inputWithLocalStorageAtom').pipe(
withLocalStorage('inputWithLocalStorageAtom'),
)

const inputWithSessionStorageAtom = atom(
'',
'inputWithSessionStorageAtom',
).pipe(withSessionStorage('inputWithSessionStorageAtom'))

const inputWithBroadcastChannelAtom = atom(
'',
'inputWithBroadcastChannelAtom',
).pipe(withBroadcastChannel('inputWithBroadcastChannelAtom'))
const inputWithSessionStorageAtom = atom('', 'inputWithSessionStorageAtom').pipe(
withSessionStorage('inputWithSessionStorageAtom'),
)

const inputIndexedDbAtom = atom('', 'inputIndexedDbAtom').pipe(
withIndexedDb('inputIndexedDbAtom'),
const inputWithBroadcastChannelAtom = atom('', 'inputWithBroadcastChannelAtom').pipe(
withBroadcastChannel('inputWithBroadcastChannelAtom'),
)
const inputIndexedDbReadyAtom = atom(false, 'inputIndexedDbReadyAtom')
onConnect(inputIndexedDbAtom, async (ctx) => {
await ctx.schedule(() => new Promise((r) => requestIdleCallback(r)))
inputIndexedDbReadyAtom(ctx, true)
return () => inputIndexedDbReadyAtom(ctx, false)
})

const inputIndexedDbAtom = atom('', 'inputIndexedDbAtom').pipe(withIndexedDb('inputIndexedDbAtom'))

export const App = () => {
const [searchLS, setSearchLS] = useAtom(inputWithLocalStorageAtom)
const [searchSS, setSearchSS] = useAtom(inputWithSessionStorageAtom)
const [searchBC, setSearchBC] = useAtom(inputWithBroadcastChannelAtom)
const [searchIDB, setSearchIDB] = useAtom(inputIndexedDbAtom)
const [inputIndexedDbReady] = useAtom(inputIndexedDbReadyAtom)

return (
<main>
<h1>Check 'Application' tab in DevTools and open multiple tabs</h1>
<p>
<label>
I'm synced using localStorage
<input
value={searchLS}
onChange={(e) => setSearchLS(e.currentTarget.value)}
/>
<input value={searchLS} onChange={(e) => setSearchLS(e.currentTarget.value)} />
</label>
</p>
<p>
<label>
I'm not synced because I use sessionStorage
<input
value={searchSS}
onChange={(e) => setSearchSS(e.currentTarget.value)}
/>
<input value={searchSS} onChange={(e) => setSearchSS(e.currentTarget.value)} />
</label>
</p>
<p>
<label>
I'm synced using BroadcastChannel
<input
value={searchBC}
onChange={(e) => setSearchBC(e.currentTarget.value)}
/>
<input value={searchBC} onChange={(e) => setSearchBC(e.currentTarget.value)} />
</label>
</p>
<p>
{inputIndexedDbReady ? (
<label>
I'm synced using IndexedDB
<input
value={searchIDB}
onChange={(e) => setSearchIDB(e.currentTarget.value)}
/>
</label>
) : (
'IndexedDB initialization...'
)}
<label>
I'm synced using IndexedDB
<input value={searchIDB} onChange={(e) => setSearchIDB(e.currentTarget.value)} />
</label>
</p>
</main>
)
Expand Down
12 changes: 6 additions & 6 deletions examples/react-persist-web/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createCtx, connectLogger } from '@reatom/framework'
import { reatomContext } from '@reatom/npm-react'
import { withIndexedDb } from '../../../packages/persist-web-storage/src/reatomPersistIndexedDb'
import { App } from './app'

const ctx = createCtx()

connectLogger(ctx)

await withIndexedDb.init(ctx)

const root = ReactDOM.createRoot(document.getElementById('root')!)
root.render(
<React.StrictMode>
<reatomContext.Provider value={ctx}>
<App />
</reatomContext.Provider>
</React.StrictMode>,
<reatomContext.Provider value={ctx}>
<App />
</reatomContext.Provider>,
)

0 comments on commit fff6d15

Please sign in to comment.