-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from mayank1513/zustand-sync
Zustand sync
- Loading branch information
Showing
14 changed files
with
280 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"persistnsync": patch | ||
--- | ||
|
||
Update keywords |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Zustand Sync Tabs [![Version](https://img.shields.io/npm/v/zustand-sync.svg?colorB=green)](https://www.npmjs.com/package/zustand-sync) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/dt/zustand-sync.svg)](https://www.npmjs.com/package/zustand-sync) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/zustand-sync) | ||
|
||
> Zustand middleware to easily persist and sync Zustand state between tabs / windows / iframes (SameOrigin) | ||
> Motivation: Recently I got cought up in several issues working with persist miggleware and syncing tabs with zustand. This is a simple light weight middleware to persist and instantly share state between tabs or windows | ||
- ✅ 🐙 (495 Bytes gZiped) < 0.5 kB size cross-tab state sharing middleware for zustand | ||
- ✅ Full TypeScript Support | ||
- ✅ solid reliability in 1 writing and n reading tab-scenarios (with changing writing tab) | ||
- ✅ Fire and forget approach of always using the latest state. Perfect for single user systems | ||
- ✅ Sync Zustand state between multiple browsing contexts | ||
|
||
> Checkout `[persistnsync](https://github.com/mayank1513/nextjs-themes/tree/main/packages/persistnsync#readme)` if you are looking for persisting state locally over reload/refresh or after closing site | ||
## Install | ||
|
||
```bash | ||
$ pnpm add zustand-sync | ||
# or | ||
$ npm install zustand-sync | ||
# or | ||
$ yarn add zustand-sync | ||
``` | ||
|
||
## Usage | ||
|
||
Simply add the middleware while creating the store and the rest will be taken care. | ||
|
||
```ts | ||
import { create } from "zustand"; | ||
import { syncTabs } from "zustand-sync"; | ||
|
||
type MyStore = { | ||
count: number; | ||
set: (n: number) => void; | ||
}; | ||
|
||
const useStore = create<MyStore>( | ||
syncTabs( | ||
set => ({ | ||
count: 0, | ||
set: n => set({ count: n }), | ||
}), | ||
{ name: "my-channel" }, | ||
), | ||
); | ||
``` | ||
|
||
⚡🎉Boom! Just a couple of lines and your state perfectly syncs between tabs/windows and it is also persisted using `localStorage`! | ||
|
||
## License | ||
|
||
Licensed as MIT open source. | ||
|
||
<hr /> | ||
|
||
<p align="center" style="text-align:center">with 💖 by <a href="https://mayank-chaudhari.vercel.app" target="_blank">Mayank Kumar Chaudhari</a></p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"use strict"; | ||
|
||
const fs = require("fs"); | ||
const path = require("path"); | ||
const packageJson = require(path.resolve(__dirname, "package.json")); | ||
|
||
const { devDependencies, scripts, ...newPackageJSON } = packageJson; | ||
newPackageJSON.main = packageJson.main.split("/")[1]; | ||
newPackageJSON.types = packageJson.types.split("/")[1]; | ||
|
||
fs.writeFileSync(path.resolve(__dirname, "dist", "package.json"), JSON.stringify(newPackageJSON, null, 2)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"name": "zustand-sync", | ||
"author": "Mayank Kumar Chaudhari <https://mayank-chaudhari.vercel.app>", | ||
"version": "0.0.0", | ||
"description": "Zustand middleware to easily sync Zustand state between tabs and windows", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"repository": "https://github.com/mayank1513/nextjs-themes/tree/main/packages/zustand-sync", | ||
"homepage": "https://github.com/mayank1513/nextjs-themes/tree/main/packages/zustand-sync#readme", | ||
"sideEffects": false, | ||
"license": "MIT", | ||
"scripts": { | ||
"build": "tsc && node createPackageJSON.js", | ||
"publish-package": "cp README.md dist && cd dist && npm publish && cd ..", | ||
"pp2": "node seo.js && cd dist && npm publish && cd ..", | ||
"pp3": "node seo1.js && cd dist && npm publish && cd ..", | ||
"pp4": "node seo2.js && cd dist && npm publish && cd ..", | ||
"p-gpr": "node createPackageJSON.js && cp README.md dist && node prepGPR.js && cd dist && npm publish && cd .." | ||
}, | ||
"funding": { | ||
"type": "github", | ||
"url": "https://github.com/sponsors/mayank1513" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^20.4.5", | ||
"typescript": "^5.1.6", | ||
"zustand": "^4.4.1" | ||
}, | ||
"peerDependencies": { | ||
"zustand": "^3 || ^4" | ||
}, | ||
"keywords": [ | ||
"web", | ||
"api", | ||
"broadcast", | ||
"channel", | ||
"sync-tabs", | ||
"sync-windows", | ||
"sync", | ||
"broadcast-channel", | ||
"hooks", | ||
"react", | ||
"react 18", | ||
"zustand", | ||
"middleware", | ||
"state", | ||
"optimized", | ||
"tiny", | ||
"typescript", | ||
"javascript" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
"use strict"; | ||
|
||
const fs = require("fs"); | ||
const path = require("path"); | ||
|
||
const packageJsonPath = path.resolve(__dirname, "dist", "package.json"); | ||
const packageJson = require(packageJsonPath); | ||
packageJson.name = `@mayank1513/${packageJson.name}`; | ||
packageJson.publishConfig = { | ||
"@mayank1513:registry": "https://npm.pkg.github.com", | ||
}; | ||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
|
||
const fs = require("fs"); | ||
const path = require("path"); | ||
|
||
const name = "zustand-sync-tabs"; | ||
const ref = "zustand-sync"; | ||
|
||
const packageJsonPath = path.resolve(__dirname, "dist", "package.json"); | ||
const packageJson = require(packageJsonPath); | ||
packageJson.name = packageJson.name.replace(ref, name); | ||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); | ||
|
||
const readMePath = path.resolve(__dirname, "dist", "README.md"); | ||
let readMe = fs.readFileSync(readMePath, { encoding: "utf8" }); | ||
readMe = readMe.replace(new RegExp(ref, "g"), name); | ||
fs.writeFileSync(readMePath, readMe); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
|
||
const fs = require("fs"); | ||
const path = require("path"); | ||
|
||
const name = "sync-zustand"; | ||
const ref = "zustand-sync-tabs"; | ||
|
||
const packageJsonPath = path.resolve(__dirname, "dist", "package.json"); | ||
const packageJson = require(packageJsonPath); | ||
packageJson.name = packageJson.name.replace(ref, name); | ||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); | ||
|
||
const readMePath = path.resolve(__dirname, "dist", "README.md"); | ||
let readMe = fs.readFileSync(readMePath, { encoding: "utf8" }); | ||
readMe = readMe.replace(new RegExp(ref, "g"), name); | ||
fs.writeFileSync(readMePath, readMe); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
|
||
const fs = require("fs"); | ||
const path = require("path"); | ||
|
||
const name = "sync-tabs-zustand"; | ||
const ref = "sync-zustand"; | ||
|
||
const packageJsonPath = path.resolve(__dirname, "dist", "package.json"); | ||
const packageJson = require(packageJsonPath); | ||
packageJson.name = packageJson.name.replace(ref, name); | ||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); | ||
|
||
const readMePath = path.resolve(__dirname, "dist", "README.md"); | ||
let readMe = fs.readFileSync(readMePath, { encoding: "utf8" }); | ||
readMe = readMe.replace(new RegExp(ref, "g"), name); | ||
fs.writeFileSync(readMePath, readMe); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { StateCreator } from "zustand"; | ||
|
||
export type SyncTabsOptionsType = { name: string }; | ||
type SyncTabsType = <T>(f: StateCreator<T, [], []>, options: SyncTabsOptionsType) => StateCreator<T, [], []>; | ||
|
||
export const syncTabs: SyncTabsType = (f, options) => (set, get, store) => { | ||
/** avoid errors on server side or when BroadcastChannel is not supported */ | ||
if (!globalThis.BroadcastChannel) { | ||
console.log("BroadcastChannel is not supported in this context!"); | ||
return f(set, get, store); | ||
} | ||
|
||
const channel = new BroadcastChannel(options.name); | ||
|
||
const set_: typeof set = (...args) => { | ||
const prevState = get() as { [k: string]: any }; | ||
set(...args); | ||
const currentState = get() as { [k: string]: any }; | ||
const stateUpdates: { [k: string]: any } = {}; | ||
/** sync only updated state to avoid un-necessary re-renders */ | ||
Object.keys(currentState).forEach(k => { | ||
if (currentState[k] !== prevState[k]) { | ||
stateUpdates[k] = currentState[k]; | ||
} | ||
}); | ||
if (Object.keys(stateUpdates).length) { | ||
channel?.postMessage(stateUpdates); | ||
} | ||
}; | ||
|
||
if (channel) { | ||
channel.onmessage = e => { | ||
set(e.data); | ||
}; | ||
} | ||
return f(set_, get, store); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/tsconfig", | ||
"compilerOptions": { | ||
"declaration": true, | ||
"esModuleInterop": true, | ||
"moduleResolution": "node", | ||
"skipLibCheck": true, | ||
"module": "CommonJS", | ||
"strict": true, | ||
"outDir": "dist" | ||
}, | ||
"include": ["src"], | ||
"exclude": ["node_modules", "dist"] | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.