{"id":18733,"library":"redux-state-sync","title":"Redux State Sync","description":"A lightweight middleware for syncing Redux state across browser tabs using the Broadcast Channel API with a fallback via pubkey's broadcast-channel. Current stable version 3.1.4. Released under MIT license, maintained actively. Key differentiator: minimal configuration, automatic tab synchronization, and built-in state initialization from other tabs. Incompatible with functions in action payloads due to structured clone algorithm.","status":"active","version":"3.1.4","language":"javascript","source_language":"en","source_url":"https://github.com/AOHUA/redux-state-sync","tags":["javascript","redux","react","localstorage","crosstab","sync","tabs","middleware"],"install":[{"cmd":"npm install redux-state-sync","lang":"bash","label":"npm"},{"cmd":"yarn add redux-state-sync","lang":"bash","label":"yarn"},{"cmd":"pnpm add redux-state-sync","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency required for middleware integration with Redux store.","package":"redux","optional":false},{"reason":"Used as a fallback for BroadcastChannel API in unsupported browsers.","package":"broadcast-channel","optional":false}],"imports":[{"note":"Package provides named exports only. CommonJS require is possible but TypeScript types require ESM import.","wrong":"const createStateSyncMiddleware = require('redux-state-sync').createStateSyncMiddleware;","symbol":"createStateSyncMiddleware","correct":"import { createStateSyncMiddleware, initMessageListener, initStateWithPrevTab, withReduxStateSync } from 'redux-state-sync';"},{"note":"Default import does not work; must use named import.","wrong":"import initMessageListener from 'redux-state-sync';","symbol":"initMessageListener","correct":"import { initMessageListener } from 'redux-state-sync';"},{"note":"Used to wrap root reducer for state rehydration from other tabs.","wrong":"const withReduxStateSync = require('redux-state-sync').withReduxStateSync;","symbol":"withReduxStateSync","correct":"import { withReduxStateSync } from 'redux-state-sync';"}],"quickstart":{"code":"import { createStore, applyMiddleware, combineReducers } from 'redux';\nimport { createStateSyncMiddleware, initStateWithPrevTab, withReduxStateSync } from 'redux-state-sync';\n\nconst config = { blacklist: ['TOGGLE_TODO'] };\nconst middlewares = [createStateSyncMiddleware(config)];\n\nconst rootReducer = combineReducers({\n  todos: (state = [], action) => state,\n  visibilityFilter: (state = 'SHOW_ALL', action) => state\n});\n\nconst store = createStore(\n  withReduxStateSync(rootReducer),\n  applyMiddleware(...middlewares)\n);\n\ninitStateWithPrevTab(store);\n\n// Now dispatch actions normally; other tabs will sync automatically","lang":"typescript","description":"Shows full setup: create middleware, wrap reducer, init state from previous tab, and blacklist an action type."},"warnings":[{"fix":"Use initStateWithPrevTab(store) alone; remove initMessageListener(store) if present.","message":"In v3, initMessageListener is no longer needed if using initStateWithPrevTab; calling both can cause double initialization.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Ensure all action payloads are plain serializable objects.","message":"Function references in action payloads will cause errors because BroadcastChannel uses structured clone algorithm which does not support functions.","severity":"gotcha","affected_versions":"all"},{"fix":"Add 'persist/PERSIST' and 'persist/REHYDRATE' to the blacklist config.","message":"When using redux-persist, PERSIST and REHYDRATE actions must be blacklisted to avoid infinite loops.","severity":"gotcha","affected_versions":"all"},{"fix":"Install @types/redux-state-sync or define your own types.","message":"TypeScript types are not bundled; you must install @types/redux-state-sync separately (now deprecated, consider adding own types).","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Check compatibility or use alternatives if targeting very old browsers.","message":"BroadcastChannel may not be supported in older browsers (e.g., Safari < 15.4). The fallback via broadcast-channel library works but has performance implications.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-25T00:00:00.000Z","next_check":"2026-07-24T00:00:00.000Z","problems":[{"fix":"Remove functions from action payloads or serialize them before dispatch.","cause":"An action with a function payload is dispatched, which violates serialization requirement.","error":"Error: Actions must be plain objects. Use custom middleware for async actions."},{"fix":"Ensure store is passed directly: initStateWithPrevTab(store); do not wrap store in another function.","cause":"initMessageListener or initStateWithPrevTab is called before the store is fully created or passed incorrectly.","error":"TypeError: store.dispatch is not a function"},{"fix":"Run npm install redux-state-sync and ensure node_modules is present.","cause":"Package not installed; or using bundler with incorrect module resolution.","error":"Module not found: Can't resolve 'redux-state-sync'"}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}