elf-sync-state
Version:
Syncs elf store state across tabs
103 lines (69 loc) • 4.4 kB
Markdown
[](https://www.npmjs.com/package/elf-sync-state) [](https://github.com/RicardoJBarrios/elf-sync-state/blob/main/LICENSE.md) [](https://github.com/RicardoJBarrios/elf-sync-state)
> Syncs elf store state across tabs
The `syncState()` function gives you the ability to synchronize an [elf store](https://ngneat.github.io/elf/) state across multiple tabs, windows or iframes using the [Broadcast Channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API).
First, you need to install the package via npm:
```bash
npm install elf-sync-state
```
To use it you should call the `syncState()` function passing the store:
```ts
import { createStore, withProps } from '@ngneat/elf';
import { syncState } from 'elf-sync-state';
interface AuthProps {
user: { id: string } | null;
token: string | null;
}
const authStore = createStore({ name: 'auth' }, withProps<AuthProps>({ user: null, token: null }));
syncState(authStore);
```
You can pass an optional `Options` object as the second parameter, which allows you to configure the following:
- `channel`: the name of the channel (default is the store name with a `@store` suffix).
- `source`: a function that receives the store and returns the data to sync. The default is `(store) => store`.
- `preUpdate`: a function to map the event message and extract the data. The default is `(event) => event.data`.
- `runGuard`: a function that determines whether the actual implementation should run. The default is `() => typeof window?.BroadcastChannel !== 'undefined'`.
- `requestState`: a boolean indicating whether the store should request the current `source` from other instances. The default is `false`.
```ts
import { syncState } from 'elf-sync-state';
import { authStore } from './auth.store';
syncState(authStore, { channel: 'auth-channel' });
```
The sync state also returns the [`BroadcastChannel`](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) object created or `undefined` if the `runGuard` function returns `false`.
```ts
import { syncState } from 'elf-sync-state';
import { authStore } from './auth.store';
const channel: BroadcastChannel | undefined = syncState(authStore);
```
The `includeKeys()` operator can be used with the `source` option to sync a subset of the state.
```ts
import { includeKeys, syncState } from 'elf-sync-state';
import { authStore } from './auth.store';
syncState(authStore, {
source: (store) => store.pipe(includeKeys(['user'])),
});
```
The `preUpdate` option can be used to intercept the [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
and modify the data to be synchronized taking into account other properties of the event.
```ts
import { includeKeys, syncState } from 'elf-sync-state';
import { authStore } from './auth.store';
syncState(authStore, {
preUpdate: (event) => {
console.log(event);
return event.origin === '' ? undefined : event.data;
},
});
```
If the `requestState` option is enabled, the store will request the initial state from other available stores on the same channel during startup.
```ts
import { syncState } from 'elf-sync-state';
import { authStore } from './auth.store';
syncState(authStore, { requestState: true });
```
The use of this library has been tested together with other Elf libraries, such as [elf-entities](https://ngneat.github.io/elf/docs/features/entities/entities), [elf-persist-state](https://ngneat.github.io/elf/docs/features/persist-state) or [elf-state-history](https://ngneat.github.io/elf/docs/features/history). I have also tried to be consistent with their programming style and documentation to help with integration.
[](https://stackblitz.com/edit/angular-elf-sync-state?devToolsHeight=33&file=src/app/todo.repository.ts) you can see an example of using all of these in an Angular application. Just open the result in two different tabs to see the library in action.
> :warning: There may be a desync due to hot reload