Ability to explicitly terminate the store
See original GitHub issueNew Features
NOTE: This could also be considered a bug report because it’s causing a memory leak.
What is the new or updated feature that you are suggesting?
I’m wanting to add a store.terminate
function to remove the Redux store entirely, close all listeners, and tell all middleware to run their own terminate functionality including the removal of that store from Redux-Devtools.
Why should this feature be included?
Already talked about a bit here: https://twitter.com/acemarke/status/1296514045789507585?s=20.
We need some way to kill of the Redux store without relying on Garbage Collection. In many cases, especially during development, the Redux store has no way of dying.
Why has no one requested this feature?
Typical use cases of a Redux store with React are it being included on a root element with the Provider
component from react-redux
. In many other applications that use Redux, there is a single store, and it’s never removed. Even in cases where there are multiple stores, the idea is that they stick around forever.
I’m building an application where Redux stores will be created and removed based on the page route. Because of this, I need some way to get rid of Redux.
It’s not entirely uncommon to want to load up and kill off Redux stores, especially when you have a component library that uses Redux, but you don’t want to have the parent application manage the Redux store. It shouldn’t matter what the component library uses internally, but if it does use Redux, it should clean up after itself.
Where does this show up?
There are 2 common practices with Redux which are problematic for this use case. The first is, Redux-Devtools, and the second is something like Redux-Observable or Redux-Saga or any custom middleware with event listeners.
In both cases, even doing store = null
doesn’t fix the issue. Either the store is still being used by Redux-Devtools or event listeners are still active in middleware with no way of knowing we want garbage collection to remove the store.
Personally, I prefer being explicit in removing the store rather than relying on garbage collection. I understand this could cause problems if you have something call dispatch
when the store no longer exists, but good code shouldn’t run into this situation. My code knows when it’s safe to terminate the Redux store, but there’s no way to notify Redux-Devtools or middleware so I keep creating new stores over and over.
Example code
https://codesandbox.io/s/redux-store-memory-leak-lg78o
Many stores created in Redux-Devtools
Redux-Devtools has no clue Redux needs to be terminated, so it listens forever and keeps those stores active in memory:
Multiple middlewares loaded
Two listeners responding to click
events because Redux didn’t notify middleware the store’s been terminated:
What docs changes are needed to explain this?
Add .terminate
to the docs on store
explaining what this does and how middleware should interact with it. In the case of Redux-Observable
, all it needs to do is unsubscribe from the root epic and all listeners will be removed automatically via RxJS.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:5
- Comments:18 (7 by maintainers)
Top GitHub Comments
My suggestion would be to first try implementing this as a store enhancer, and see how something like that works out.
This is what I’m proposing:
@@TERMINATE
action that tells middleware to close any active listeners and callbacks.store.dispatch({ type: '@@TERMINATE' })
.store.terminate()
.store.terminate()
function which loops through allstore.onTerminate(callback)
callbacks in middleware so they know when to close any active listeners and callbacks. This doesn’t just affect middleware. Anything like react-redux can also remove references tostore
if it’s still got them somewhere.Consumers of Redux that have a
store
need to dostore = null
to get rid of the reference to it in their own apps. As soon as all references tostore
are removed, Redux (including its middleware) will be garbage collected.That’s the goal of this whole issue. We need some way of removing Redux from memory using garbage collection. Normally this works fine, but since Redux allows for middleware, we need to also notify middleware that Redux has been terminated; thus, they should also stop any active
addEventListener
,setInterval
, andsetTimeout
callbacks. Doing so will successfully allow Redux to garbage collect.