molefrog / molefrog/wouter

Avoiding race conditions when updating search

Open
#432 6 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
TypeScript
Stars
7.9k
Forks
190
Avg merge
12h 50m
Merged PRs (30d)
3

Description

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:

const useQueryParam = (param: string) => {
  const [loc, navigate] = useLocation();
  const search = useSearch();

  const value = useMemo(() => new URLSearchParams(search).get(param), [search, param]);
  const setter = useEvent((newValue: string | null) => {
    const params = new URLSearchParams(search);
    if (setter === null) params.delete(param);
    else params.set(param);

    navigate(`${loc}${params.toString()}`);
  };

  return [value, setter] as const;
};

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 the setter 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 of search 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 to navigate and the second reference to search; 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?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No files or tests are named. Start by tracing useSearch, useLocation, and navigate in the router implementation, then review issue #368 and the existing tests. A maintainer would need to define the supported race-safe update behavior and acceptance criteria before implementation can begin.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.