wouter icon indicating copy to clipboard operation
wouter copied to clipboard

Expose a `subscribe` function suitable for React's `useSyncExternalStore`

Open HansBrende opened this issue 3 years ago • 1 comments

The only thing missing from the use-location package is a way to actually subscribe to location updates. Let's say such a subscribe function was exported.

Then users could do the following:

import {subscribe} from "wouter";
const getCurrentValueOfMySearchParam = () => ... extract some stuff from window.location

function MyComponent() {
    const currentSearchValue = React.useSyncExternalStore(subscribe, getCurrentValueOfMySearchParam);
}

The nice thing about this potential ability is that you do NOT re-render if something in the URL changes that you don't care about!!!

Background: useSyncExternalStore is React's replacement for its previous attempt at a hook for listening to external subscriptions, called useMutableSource, which in turn was a replacement for its previous package called useSubscription which was a replacement for the gist created by Brian Vaughn linked to in this comment.

In fact, all of the code surrounding that comment can likely be replaced by a single call to useSyncExternalStore.

useSyncExternalStore is part of React 18; however there is a shim package available for previous versions (so I don't think that would break your 0-dependency achievement since it is technically part of React.)

HansBrende avatar Jan 31 '22 01:01 HansBrende

👍

cbbfcd avatar Feb 14 '22 09:02 cbbfcd

Nice! I think we could switch to useSyncExternalStore entirely in the next major release. I guess we can support React 18 as a default target, all previous versions can use shims.

molefrog avatar Nov 02 '22 18:11 molefrog

FYI: I've updated our example from the docs with hash-based location to use useSyncExternalStore https://github.com/molefrog/wouter#customizing-the-location-hook

molefrog avatar Nov 16 '22 10:11 molefrog

@molefrog cool! Note that you don't need useCallback at all in that example, because it contains no references to other properties. I would write the hash one like this:

const navigate = (to) => void (window.location.hash = to);
const useHashLocation = () => {
    ....
    return [location, navigate];
}

HansBrende avatar Nov 16 '22 16:11 HansBrende

Thanks, updated the example.

molefrog avatar Nov 18 '22 10:11 molefrog