New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
middleware's getState always returns optional #389
Comments
Making We can avoid the retain cycle you speak of by not pre-computing the internal dispatch function at |
Sorry, I haven't explained myself very well. I know how to make the let getState: () -> State = { [unowned self] self.state! } should be enough and, as you already know, if the store gets deallocated and a middleware still uses I guess my real question is how can we make I think something like this:
could be a good idea, but instead of passing it the whole store, just passing it an instance of a lightweight version of the store (with the This I didn't get it, could you elaborate?
|
Its not a straight swap over, but something like changing Middleware to:
Then in and the dispatch function creation becomes self.dispatchFunction = { store in
middleware
.reversed()
.reduce(
{ [unowned self] action in
self._defaultDispatch(action: action) },
{ dispatchFunction, middleware in
return middleware(store)(dispatchFunction)
})
} then finally There are many other difficulties in making a switch like this -- We actually want to restrict to I believe all the issues are workable, though I'm not sure its valuable enough for the effort required. |
Interesting. Following this approach, maybe instead of passing it the whole store, we can pass it only the tuple with the two functions the current middleware needs? This could simplify the types, I guess, but recalculating the dispatch function for every action dispatched wouldn't be performant (although we could create the function only once, lazily). I need to play with this to really know that it breaks the retain cycle, as it's still not clear to me, and see if the code could be simplified. I do think it makes sense Thanks for the time you're putting into this issue, @mjarvis, you're great. |
If I understood you correctly, this approach might break some middlewares' current behavior.
let middleware: Middleware<State> = { dispatch, getState in
// both, this
return { next in
// and this closures are called only once on Store init
// thus you can store some local state here
return { action in
// and this closure is called for every action
}
}
} But if you put whole middleware appliance into |
@a-voronov Ah! Thats a very interesting point! a second downside to that is the two extra closure calls per middleware per action could be a not-insignificant performance hit, as well. |
I use ReSwift's middleware a lot, as I consider it one of the killer features of this library, and I've always wondered why the
getState
function we pass to the middleware returns the state as an optional value, having to write the boilerplate of unwrapping it every time we want to access it, which is super annoying.I've been thinking about this and, in theory, it doesn't need to be like that, as we always supposed to have a non-optional state once we've instantiated the store, either because we pass a preloaded state to it, or because each reducer creates its own initial value after the init action has been dispatched (which happens at store's init time). In fact, you will never see anyone checking if the state is not
null
before accessing it in the original Redux library, written in the super dangerous JavaScript.This past weekend, I've been trying to make the changes needed to make
getState
non-optional, and after accommodating the code a bit and adding a couple of tests, I've realised this is not possible a priori, so we can avoid a retain cycle that would make the store impossible to deallocate. I've been trying to use the techniques described here, but I couldn't make it work.What do you think? Should this be possible at all?
The text was updated successfully, but these errors were encountered: