From: https://twitter.com/mjackson/status/1246248620023623680
Hi, I've been developing a library for React Suspense Render-as-You-Fetch with React Router.
https://github.com/dai-shi/react-suspense-router
I started with v5, but soon v6-alpha is available. It's so clean, and I like it!
Thanks to v6, my library is just a thin wrapper around it, but I need three more hooks to implement it. Here, I briefly describe them so that we can discuss any workarounds.
This is to return the pending state from useTransition. It would be used to show pending state on route change. As I think the use case is not limited to my library, but any apps in the future, I filed a PR.
https://github.com/ReactTraining/react-router/pull/7130
As I need to patch useRoutes, it requires to get the parent pathname. This is not exposed, but I did an undesired workaround.
const EMPTY_PATHNAME = { pathname: null };
const usePathname = () => useResolvedLocation(EMPTY_PATHNAME).pathname;
There might be other use cases than mine.
This is controversial. I need to call my listeners in the same startTransition in Router.
I did try various hacks without any success.
I don't know if there's any other use cases. If I were the author of RR, I wouldn't expose it. For now, I ended up with forking react-router.
https://github.com/dai-shi/react-router/compare/dev...dev-for-lib
let listen = React.useCallback(fn => {
childListeners.current.push(fn);
fn(history.location); // call once with current location
return () => {
let index = childListeners.current.indexOf(fn);
childListeners.current.splice(index, 1);
};
}, [history]);
/**
* Returns the listen in Router (for library use)
* Same as history.listen but called in startTransition
*/
export function useListen() {
return React.useContext(LocationContext).listen;
}
I'm not sure if my library will be able to build on top of preload.
A useHash will also be good. It's a common use case that hash is used for controlling modals.
function App() {
const [hash, setHash] = useHash();
return (
<div>
<button onClick={() => setHash('#new')}>Open modal</button>
<SomeFormModal show={hash === '#new'} />
</div>
);
}
export function useHash() {
const { hash, ...location } = useLocation();
const navigate = useNavigate();
function setHash(newHash) {
navigate({ ...location, hash: newHash });
}
return [hash, setHash];
}
I'd like to contribute but I'm not good at testing. :(
Please don't move away from class-based components entirely. My experience with hooks has so far been a hellacious fiasco. I can't figure out why, but for some reason, hooks are causing all sorts of double and quadruple renders and in my scenario, multiple of the same route getting pushed onto the history stack.
@FullstackJack That is usually a sign of incorrect dependencies on useEffect or chained useState->setState calls. That's really on you to figure out, but it's not something caused by the library. I'd make sure you have eslint-plugin-react-hooks installed to ensure some safety when using them.
Access to the navigation action is needed. There is now useLocation() but no useAction() to know if the previous navigation was a push, pop or replace. This is needed in many apps for deciding how to behave when a new page comes up. E.g. restore scroll position, load data vs. use data from cache, etc.
Seconding the need for something like useListen or useAction, described above. In my app that's using v5, I setup a listener like this:
const history = useHistory();
// a placeholder function, for completeness's sake
const onRouteChange = (path) => {};
const unsubscribe = history.listen((loc, act) => {
if (act === 'PUSH' || act === 'REPLACE') {
const { pathname: curPathname, search } = loc;
onRouteChange(`${curPathname}${search}`);
}
unsubscribe();
});
The function onRouteChange is a key-feature for my application and it's important that we only trigger it when the history method called is pushing or replacing. I don't see an alternative way to accomplish something this otherwise with the APIs provided by v6 at the moment, which prevents me from upgrading to the latest and greatest.
Otherwise, v6 looks amazing and I can't wait to upgrade to it.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
You can add the fresh label to prevent me from taking any action.
Most helpful comment
Seconding the need for something like
useListenoruseAction, described above. In my app that's using v5, I setup a listener like this:The function
onRouteChangeis a key-feature for my application and it's important that we only trigger it when the history method called is pushing or replacing. I don't see an alternative way to accomplish something this otherwise with the APIs provided by v6 at the moment, which prevents me from upgrading to the latest and greatest.Otherwise, v6 looks amazing and I can't wait to upgrade to it.