Hello, thank you for this wonderful library.
Is it possible to haveuseMatch,useLocation hooks for us?
Right now, the <Match /> and <Location /> are render props, it will be really nice to have hooks version to reduce wrappers.
Thank you!
I put this together to test it out. I'd be curious to hear any feedback, as I've just started getting into hooks.
import {useState, useEffect} from 'react';
import {globalHistory} from '@reach/router';
export function useLocation() {
const newState = {
location: globalHistory.location,
navigate: globalHistory.navigate,
};
const [state, setState] = useState(newState);
useEffect(() => setState(newState), [newState.location]);
return state;
}
@mikestopcontinues your solution only gave me the initial location but would not update when the location changed. I modified it slightly so that it updates the location on every update.
import { useState, useEffect } from 'react';
import { globalHistory } from '@reach/router';
const useLocation = () => {
const initialState = {
location: globalHistory.location,
navigate: globalHistory.navigate,
};
const [state, setState] = useState(initialState);
useEffect(() => {
const removeListener = globalHistory.listen(params => {
const { location } = params;
const newState = Object.assign({}, initialState, { location });
setState(newState);
});
return () => {
removeListener();
};
}, []);
return state;
};
export default useLocation;
Nice, @mmende!
If reach added LocationContext as an export, I suspect this would be an even shorter snippet, using useContext
Yes probably... But I'd also love to see these hooks directly exposed by the primary api
@mmende I agree, I think it would be great to expose these as explicit hooks for the API.
Is anyone on this issue working on a PR? Or have any way of getting in touch with maintainers, to see if it will be accepted?
There's a PR here: https://github.com/reach/router/pull/201
I contacted @ryanflorence on Twitter, not sure if he saw it. I hope he can get around to merging it, it's 1 line, I've tested it locally and it seems to work.
From a quick look, it looks like this project is dead. Last commit was in Feb... I'll be using my own fork in the meantime.
Another advantage of a hook is to avoid globalHistory in the scenario that a different history instance is passed with LocationProvider, such as a memory history.
Has anyone written a PR or tests in an attempt to get this added?
@peter-mouland yeah #201. I tried to contact the project maintainer (via Spectrum) to see if it was an addition that would likely get merged (as per the CONTRIBUTING.md), however I got no response.
Nor does it look like @maktouch has had any success.
I think I saw @ryanflorence tweet that he would be getting some time soon to focus on open-source projects?
Also consider that this project will eventually fade away after this announcement, so contributions that get merged may be sparse, and it may be worth considering doing them in react-router instead.
If you don't want to deal with the complexity of subscriptions in concurrent mode, you could use the new use-subscription package for this?
import { useMemo } from "react";
import { useSubscription } from "use-subscription";
import { globalHistory } from "@reach/router";
function useLocation() {
const subscription = useMemo(
() => ({
getCurrentValue: () => globalHistory.location,
subscribe: callback => globalHistory.listen(callback)
}),
[]
);
return useSubscription(subscription);
}
Agree with @afenton90, in that the hook based API will be a part of react-router per this blog post
Hey everyone. the example @bvaughn provided works perfectly with any csr app. But it doesn't work correctly if you are using @reach/router on a server-side rendered website And I found it quite hard to solve the issue without having access to the @reach/router's private LocationContext.
We should of course use the official hooks API introduced in the recent versions of the react-router, But meanwhile, if you are trapped with an older version, here is a trick I've used in one of my projects.
(CAUTION: Be careful with this solution, it may break after any minor version upgrade of react or @reach/router)
export const useLocation = () => {
const LocationContext = React.useMemo(() => {
// DON'T TRY THIS AT HOME. REACHING INTO INTERNALS TO GET ACCESS TO THE LOCATION CONTEXT
const Return = Location({});
return Return.type._context || Return.type;
}, []);
const { location } = React.useContext(LocationContext);
return location;
};
Most helpful comment
@mikestopcontinues your solution only gave me the initial location but would not update when the location changed. I modified it slightly so that it updates the location on every update.