-
-
Notifications
You must be signed in to change notification settings - Fork 154
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
Avoiding race conditions when updating search #432
Comments
BTW I'm using Preact (annoyingly, with |
Hello, it took me some time to wrap my head around it, but I think I finally got the idea. A just wanted to confirm: is this something hypothetical or a real case that you were able to reproduce? Also, assuming that instead of calling 'navigate' you worked with context value (via state), wouldn't this also create race condition? |
If we have two components that set state to different values simultaneously, this might create some ambiguity in my opinion, because React doesn't guarantee the exact order of useEffect invocations (I suppose this is where the state is changed). |
So yeah this is a real-life situation. Unfortunately, it's in a private repo so I can't share exactly the implementation I've gone with but basically, not worrying specifically about two things trying to set the same property but separate properties. E.g., one component gets and sets "name" from the query string and another gets and sets "email"; but by simply having a string coming from const search = useSearch();
// If an event like this is called from two different components near-enough
// that a rerender is not triggered, `search` will not have the other component's
// value on it, so `params.toString()` will omit that value
useEvent((email: string) => {
const params = new URLSearchParams(search);
params.set('email', email);
navigate(loc + '?' + params.toString();
}); The way these race conditions are generally resolved in other [p]react hooks is by allowing for callbacks, such as in What I've ended up doing is basically creating a wrapper context that just keeps a queue of updates to apply to the search string one at a time, popping from the queue on each render (applying from the queue causes a re-render since |
I see, makes sense now. Have you tried wrapping |
:( looks like preact's implementation is just a straight passthrough to the internal function. I'm not sure it would solve this problem—because it seems like it's more intended for synchronous code within one component rather than between components—but it does seem like it could, since the synchronous nature would presumably be blocking. I'm just not sure |
I see #368 which may be related but I can't find anything that addresses simultaneous or near-simultaneous updates to the
search
. I'm probably going to end up implementing my own solution in my codebase in one way or another but I thought I'd bring it up here in case there's already thought on how this can be managed.I have a function called
useQueryParam
that does a bunch of coercion etc but at its core it's basically:It basically behaves like
useState
but persists to the query string.With the prior version of Wouter, I had just hooked directly into
window.location.search
inside thesetter
so the params were always the latest when setting.But with the latest version, for consistency and better testability (JSDOM is notoriously … not useful) I wanted to migrate to
useSearch
, which can consume from the<Router>
context which can be in-memory. But that means that if two setters execute simultaneously (say, setting a default value on page render, from different subcomponents – making it hard to batch them in other ways), they encounter a race condition where both setters are operating from the same value ofsearch
so the second one overwrites the changes of the first.As I understand it, even though
useEvent
will use the values from the latest invocation of the hook, the hook will only be invoked on a re-render and re-render may not have triggered between the first call tonavigate
and the second reference tosearch
; am I conceptualizing that right?Does this problem explanation make sense? Again, I don't think this blocks me, because a) I just won't upgrade Wouter until I can sort this out and b) I have a number of possible homegrown solutions in mind; but I'm wondering if this is a solved problem and I missed it, or a problem that you're thinking about?
The text was updated successfully, but these errors were encountered: