You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An issue with Flux and Redux is the inability to garbage collect stores. Today, Undux suffers from the same issue: because each store is a singleton defined at the top level in a module, there's no way to safely garbage collect it today.
This is an issue when using Undux in complex applications with many React roots (ie. ReactDOM.render is called for lots of mount points), like facebook.com. In applications like that, if a particular root makes use of a particular Undux store, it's desirable to GC the store when its corresponding React root unmounts.
One way to do that is to speciate withStore into two kinds of withStore:
A withStore that indicates that the component that is wrapped is a React root. When that component unmounts, we should GC the store. Let's call it withStoreRoot.
A withStore that indicates that the component this is wrapped is not a React root, and is just a regular store-consuming component. This is how withStore behaves today.
This approach would also mean forbidding declaring and using store at the top level. Instead, we'd expose a way to create a "store factory", and store could only be used in React components and Undux Plugins. This has the downside of making writing Undux Actions more painful, but could ultimately be a good way to enforce good architecture (similar to #36).
If we go with this approach, we need a way to enforce that all withStore calls for a given store are descendents in the React tree of their corresponding withStoreRoot call. Otherwise, we run into a weird case where a root unmounts, the store is GC'd, but there's still a child component holding onto a stale StoreSnapshot prop.
This kind of enforcement is really hard. We can do it at runtime (similar to how React.createContext works), but ideally we want to do it at compile time. Compile time enforcement with a type system doesn't seem to be possible: neither TypeScript nor Flow support recursively constraining JSX child types (microsoft/TypeScript#21699). So we're stuck with runtime enforcement for now.
An issue with Flux and Redux is the inability to garbage collect stores. Today, Undux suffers from the same issue: because each store is a singleton defined at the top level in a module, there's no way to safely garbage collect it today.
This is an issue when using Undux in complex applications with many React roots (ie.
ReactDOM.render
is called for lots of mount points), like facebook.com. In applications like that, if a particular root makes use of a particular Undux store, it's desirable to GC the store when its corresponding React root unmounts.One way to do that is to speciate
withStore
into two kinds ofwithStore
:withStore
that indicates that the component that is wrapped is a React root. When that component unmounts, we should GC the store. Let's call itwithStoreRoot
.withStore
that indicates that the component this is wrapped is not a React root, and is just a regular store-consuming component. This is howwithStore
behaves today.This approach would also mean forbidding declaring and using
store
at the top level. Instead, we'd expose a way to create a "store factory", andstore
could only be used in React components and Undux Plugins. This has the downside of making writing Undux Actions more painful, but could ultimately be a good way to enforce good architecture (similar to #36).If we go with this approach, we need a way to enforce that all
withStore
calls for a given store are descendents in the React tree of their correspondingwithStoreRoot
call. Otherwise, we run into a weird case where a root unmounts, the store is GC'd, but there's still a child component holding onto a staleStoreSnapshot
prop.This kind of enforcement is really hard. We can do it at runtime (similar to how
React.createContext
works), but ideally we want to do it at compile time. Compile time enforcement with a type system doesn't seem to be possible: neither TypeScript nor Flow support recursively constraining JSX child types (microsoft/TypeScript#21699). So we're stuck with runtime enforcement for now.Exploration here: https://gist.github.com/bcherny/f360f417e8768558684ec3e379f9e354
The text was updated successfully, but these errors were encountered: