redux-state-sync icon indicating copy to clipboard operation
redux-state-sync copied to clipboard

Broadcast channels not systematically closed ? Leak ?

Open odusseys opened this issue 2 years ago • 3 comments

I am running into a very strange bug, which I am having trouble reproducing consistently. For background I am using the initStateWithPrevTab' helper to reinitialize state with previous tabs upon page load. My overall code looks like this (I have only one reducer, dataFetching`, and corresponding actions which only act on that reducer, which are whitelisted by redux-state-sync)

const persistConfig: PersistConfig<RootState> = {
  key: "root",
  storage,
  timeout: 0,
  stateReconciler: autoMergeLevel1,
  blacklist: ["dataFetching"],
};

const persistedReducer = persistReducer(
  persistConfig,
  withReduxStateSync(rootReducer) as any
);


const dataFetchingSync = createStateSyncMiddleware({
  whitelist: DATA_FETCHING_ACTION_TYPES,
});

export const store = createStore(
  persistedReducer,
  applyMiddleware(logger, dataFetchingSync)
);

initStateWithPrevTab(store);

Occasionally, I will run into issues when reloading a page where the redux state is immediately reset to its previous value, including the non-persisted reducer, which seemed strange. Upon investigation, what happens is the following

  • Upon page load, a &_GET_INIT_STATE action is dispatched
  • Immediately after, a &_RECEIVE_INIT_STATE is received, with the same window uuid, and the previous value for the state, before reload
  • the state is thus overriden by that value

This means that there is no way, when that happens, to refresh the state in memory. Closing all tabs does not resolve it. Closing Chrome, however, does - and no more _RECEIVE_INIT_STATE action is received

I cannot reproduce this consistently and it happens randomly. I cannot see a simple explanation for this, but I don't understand how, after reload, the state can still be available somewhere, and dispatched through the BroadcastChannel. I can't find a trace of that state anywhere in application storage so it must be in memory. I am wondering if, by any chance, the BroadcastChannel created is not being closed upon reload, thus leading to a leak where, after reloading, it is still present with its original listener, and dispatches a state which has been kept in memory. The BroadCastChannel API docs explicitly say that the channel should be closed when no longer used in order to avoid memory leaks. This does not seem to be the case in the source code. Should there perhaps be a listener for window.unload to close the channel ?

odusseys avatar Feb 09 '22 08:02 odusseys