-
Notifications
You must be signed in to change notification settings - Fork 642
Fix double update on history.pushState #109
Conversation
Stopping those cycles ain't easy — too many edge cases ;) |
We shouldn't need this code, this should have done it: // Also set `lastRoute` so that the store subscriber doesn't
// trigger an unnecessary `pushState` on load
lastRoute = initialState The initial action that is dispatched through the system should set the I'd prefer to keep the syncing as possible (I'm sure you do too) and if we do something like this we might as well look into changing how the whole |
This PR doesn't solve the issue for me as reported in #108 edit: although, this behaviour I'm seeing is when both reduxSimpleRouter is integrated as well as a route specific dispatch is invoked within |
@jlongster This isn't related to
I.e. EDIT: Btw, this is every time. If you
|
@tomatau So it still gets double applied? Could you create a small reproducible example? |
@kjbekkelund I've edited my comment to explain the more of the specifics around the problem. The complete example is linked in the OP of the original issue. |
@jlongster The problem with |
Hm, I'll play around with it and see what I find out |
@kjbekkelund the code I mentioned before was there to fix Just explaining the intent of the code; I haven't looked deeply at the problem here yet. |
@jlongster Yep, but it only sets it initially. But if you later if(lastRoute.changeId !== routing.changeId ||
!locationsAreEqual(lastRoute, routing)) { returns |
7252178
to
ca53f60
Compare
Oh, I see. I feel like this PR might work but we should think about removing or changing the other checks; seems like if we do this it might stop the cycle in most cases? I also had another idea before: the new routing state, when changed, is always a different instance. So we could also just do Do you think you could look into the above? If EDIT: fixed naming of |
I'll be more active next week, as I'll be back from a work trip! We can hopefully move to rackt then too. |
@jlongster We already have problems with |
I don't think that's a systemic problem of Last time I tried that it was really hard to debug problems though. |
Isn't the whole problem that It seems like the root cause of all the cycles is that there are 2 sources of truth. Couldn't there be a different solution? Give Router a "ReduxHistory" object that is initialized from the real History object. When Router writes to the ReduxHistory, it generates redux actions (instead of updating the real history object directly). When Router listens to the ReduxHistory object, the listen subscription is delegated to the real History object. When the redux store updates, the changed state is pushed into the real history object, which will then trigger Router to update. Net effect is now there's a single source of truth and no cycles to fix. Is there something wrong with this approach? |
Hi @bman654, thanks for the input! Are you talking about react-router here? I'm not sure I understood the flow here. Today we don't do anything related to react-router itself. We only rely on As far as I can tell what you describe is basically what the library does today, but without going through react-router. (It might be that would help here, so it would be great to get more information about how you see this working) Could you draw up how this would work for these two cases:
Today, 1 generates redux actions, so it triggers 2, and 2 updates the URL, so it triggers 1. I've tried to draw it up (marking flow 1 as (What we try to do today is hit all four of these once — because we can't selectively listen for I think we inherently have two sources of truth for this lib: the URL and the router state in the redux store. Keeping these two in sync is what we're trying to solve. |
I'm referring to your first use case. What is actually happening in #108 is the user is clicking on a The problem is that both This pull request adds some logic to detect the recursion and prevent step 7 from occurring, which would break the loop. But, from looking at the code, it seems like this isn't the only code related to breaking cycles. I'm just proposing a different synchronization mechanism that has no cycles, so the information only flows in one direction. In this version, this library would consume the history object and treat it as a write-only object to which it will write route changes (which ultimately get reflected in the browser url field). This library gives back a Mock History object that transforms mutation requests into Redux Actions, and subscribes to the Redux store to notify listeners. Your scenario 2 works exactly the same as it currently works, except now there are no cycles to stop. Action updates store. Store notifies subscriber. One subscriber updates real History. Second subscriber updates MockHistory, which Router is listening to. And now scenario 1 also no longer has any cycles. Router tries to modify history. Action is dispatched. Store is updated. Store subscriber updates real History. Store subscriber updates MockHistory, which Router is listening to. I'll see if I can throw something together around this concept tonight. |
I guess what my proposal really is: a ReduxHistory object that you can use with React-Router to make it redux-aware. |
Not sure how this would work. You have both a |
I don't understand what you mean by "user randomly updating the URL". You mean if the user literally goes into the URL bar and changes it? Doesn't that just cause the browser to load the new URL? Doesn't seem to trigger an event when I try it. |
Try with But either way, just to be sure I've understood, what you're proposing is for the user to not use |
Actually my idea is to use history library, but just as a history enhancer.
But anyway I just realized what you meant. User could click browser back and forward buttons. My idea won't work with that without listening to the history object and then the cycles are back.
|
Agreed. The difficult thing is getting everything "to match up" — I always end up with a test or two that fails ;) Have been playing around a little bit with ideas without coming up with a simple solution. |
Closing this in favour of #129 |
Not the nicest tests or the nicest implementation, but a suggestion for how to handle the double updating reported in #108.
(Of course, if we end up going in this direction I'll add in some comments and tune the tests)
Anyone else got ideas that don't break any of the other tests? I'll try to play around with it a bit more too.