redux-persist-crosstab icon indicating copy to clipboard operation
redux-persist-crosstab copied to clipboard

Support for localForage (and other non-localStorage engine)

Open mattmcdonald-uk opened this issue 8 years ago • 5 comments

This package won't work for me, and I believe it's due to using localForage instead of localStorage which means no storage events are being fired (https://github.com/localForage/localForage/issues/244).

Is there any way to have redux-persist fire an event that can be listened to instead?

mattmcdonald-uk avatar Nov 03 '16 16:11 mattmcdonald-uk

@rt2zz Any updates on this?

TheNeikos avatar Feb 04 '17 00:02 TheNeikos

afaik indexeddb has no way to listen for changes (other than polling). If there is a solution, making redux-persist-crosstab support it should be trivial. More info here: https://github.com/localForage/localForage/issues/244

If you have any other ideas for how this can be done let me know I am happy to integrate.

rt2zz avatar Feb 06 '17 02:02 rt2zz

Ah so this is why it's not working for me. I think I have a solution. How about everytime indexeddb change, which trigger "inbound", you set value on localStorage, so that another tabs will be notified that indexeddb is changed.

localStorage acts as the bridge.

Altiano avatar Sep 29 '17 03:09 Altiano

It should also be possible to use BroadcastChannel to subscribe/emit information about changes to the storage (ATM supported in Chrome and Firefox) or MessageChannel

piotr-cz avatar Jan 05 '18 09:01 piotr-cz

This is my take on implemetation of crosstab state using BroadcastChannel, code should be placed inside configureStore function as it requires access to store and persistConfig objects.

Works wis Redux Persist v5

import { REHYDRATE } from 'redux-persist/lib/constants'

if (window.BroadcastChannel) {
  const csBc = new window.BroadcastChannel('crosstabState-channel')
  let dispatchingSelf = false

  store.subscribe(() => {
    // Prevent endless loop when rehydration was called in this tab
    if (dispatchingSelf) {
      return dispatchingSelf = false
    }

    // Post state to channel
    csBc.postMessage(store.getState())
  })

  csBc.addEventListener('message', ev => {
    dispatchingSelf = true

    // Rehydate store with received state
    store.dispatch({
      key: persistConfig.key,
      payload: ev.data,
      type: REHYDRATE,
    })
  })
}

BroadcastChannel won't broadcast to inself, but store rehydration will trigger new store subscribe callback, so there need to be a flag to distinguish that (I've tried to attach new properties to state or piggy-back on _persist value when dispatching rehydration but that didn't work)

References:

piotr-cz avatar Jan 05 '18 10:01 piotr-cz