mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-19 05:45:01 -04:00
Improve useZodRouteParams (#1917)
* Better `useZodRouteParams` * cleanup message
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { type Router } from '@remix-run/router';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { createRoutes } from './app';
|
||||
@@ -9,6 +10,9 @@ export const RoutingContext = createContext<{
|
||||
routes: ReturnType<typeof createRoutes>;
|
||||
} | null>(null);
|
||||
|
||||
// We split this into a different context because we don't want to trigger the hook unnecessarily
|
||||
export const RouterContext = createContext<Router | null>(null);
|
||||
|
||||
export function useRoutingContext() {
|
||||
const ctx = useContext(RoutingContext);
|
||||
|
||||
@@ -16,3 +20,10 @@ export function useRoutingContext() {
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
export function useRouter() {
|
||||
const ctx = useContext(RouterContext);
|
||||
if (!ctx) throw new Error('useRouter must be used within a RouterContext.Provider');
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { z } from 'zod';
|
||||
import { useRouter } from '~/RoutingContext';
|
||||
|
||||
// This is hook basically implements a custom version of `useParams`.
|
||||
// If we use `useParams` directly, every time *any* param changes the current component will rerender so the hook reruns.
|
||||
//
|
||||
// With this improved implementation the component will only rerender if the change in parameter causes a change in the output of the Zod schema.
|
||||
//
|
||||
// We use this hook to get the library ID high up in the React tree so this reduces unnecessary rerenders of a large portion of the app.
|
||||
export function useZodRouteParams<Z extends z.AnyZodObject>(schema: Z): z.infer<Z> {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const params = useParams();
|
||||
return useMemo(() => schema.parse(params), [params, schema]);
|
||||
const router = useRouter();
|
||||
const [result, setResult] = useState(() => {
|
||||
const params = router.state.matches[router.state.matches.length - 1]?.params || {};
|
||||
return schema.parse(params);
|
||||
});
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
router.subscribe(({ matches }) => {
|
||||
const routeMatch = matches[matches.length - 1];
|
||||
const params = routeMatch ? (routeMatch.params as any) : {};
|
||||
setResult(schema.parse(params));
|
||||
}),
|
||||
[router, schema, setResult]
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Devtools } from './components/Devtools';
|
||||
import { WithPrismTheme } from './components/TextViewer/prism';
|
||||
import ErrorFallback, { BetterErrorBoundary } from './ErrorFallback';
|
||||
import { useTheme } from './hooks';
|
||||
import { RoutingContext } from './RoutingContext';
|
||||
import { RouterContext, RoutingContext } from './RoutingContext';
|
||||
|
||||
export * from './app';
|
||||
export { ErrorPage } from './ErrorFallback';
|
||||
@@ -53,21 +53,23 @@ export function SpacedriveRouterProvider(props: {
|
||||
};
|
||||
}) {
|
||||
return (
|
||||
<RoutingContext.Provider
|
||||
value={{
|
||||
routes: props.routing.routes,
|
||||
visible: props.routing.visible,
|
||||
currentIndex: props.routing.currentIndex,
|
||||
maxIndex: props.routing.maxIndex
|
||||
}}
|
||||
>
|
||||
<RouterProvider
|
||||
router={props.routing.router}
|
||||
future={{
|
||||
v7_startTransition: true
|
||||
<RouterContext.Provider value={props.routing.router}>
|
||||
<RoutingContext.Provider
|
||||
value={{
|
||||
routes: props.routing.routes,
|
||||
visible: props.routing.visible,
|
||||
currentIndex: props.routing.currentIndex,
|
||||
maxIndex: props.routing.maxIndex
|
||||
}}
|
||||
/>
|
||||
</RoutingContext.Provider>
|
||||
>
|
||||
<RouterProvider
|
||||
router={props.routing.router}
|
||||
future={{
|
||||
v7_startTransition: true
|
||||
}}
|
||||
/>
|
||||
</RoutingContext.Provider>
|
||||
</RouterContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user