Gathering detailed insights and metrics for dk-react-mobx-router
Gathering detailed insights and metrics for dk-react-mobx-router
Gathering detailed insights and metrics for dk-react-mobx-router
Gathering detailed insights and metrics for dk-react-mobx-router
npm install dk-react-mobx-router
Typescript
Module System
Node Version
NPM Version
TypeScript (92.69%)
JavaScript (4.68%)
HTML (1.67%)
CSS (0.75%)
SCSS (0.19%)
Shell (0.02%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
21 Stars
248 Commits
3 Forks
3 Watchers
1 Branches
1 Contributors
Updated on Jun 02, 2025
Latest Version
3.4.13
Package Id
dk-react-mobx-router@3.4.13
Unpacked Size
138.61 kB
Size
25.65 kB
File Count
51
NPM Version
lerna/8.1.2/node@v22.7.0+x64 (linux)
Node Version
22.7.0
Published on
Jun 02, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
3
3
[!WARNING]
It's fine if you use this library from NPM package with a static versioning in case you want it for some pet-project or to test it's capabilities.But for production use it's strongly recommended to create a fork, because I do not write Changelogs and may break / add some functionality without notice.
beforeEnter
and beforeLeave
() => import('/some-page')
)<Route path="..." />
inside React componentsThe setup consists of three parts:
dk-react-mobx-router
, dk-mobx-stateful-fn
and mobx-react-lite
/ mobx-react
routes.ts
1import { createRouterConfig } from 'dk-react-mobx-router'; 2 3export const routes = createRouterConfig({ 4 home: { 5 path: '/', 6 loader: (() => import('./pages/home')), 7 }, 8 static: { 9 path: '/static', 10 loader: (() => import('./pages/static')), 11 }, 12 dynamic: { 13 path: '/page/:foo/id/:bar', 14 params: { 15 foo: (value) => value.length > 2, 16 bar: (value) => value.length > 0, 17 }, 18 loader: (() => import('./pages/dynamic')), 19 }, 20 // this page is necessary 21 error404: { 22 path: '/error404', 23 props: { errorCode: 404 }, 24 loader: (() => import('./pages/error')), 25 }, 26 // this page is necessary 27 error500: { 28 path: '/error500', 29 props: { errorCode: 500 }, 30 loader: (() => import('./pages/error')), 31 }, 32});
1import { makeAutoObservable } from 'mobx'; 2import { InterfaceRouterStore } from 'dk-react-mobx-router'; 3 4import { routes } from 'routes'; 5 6type TInterfaceRouterStore = InterfaceRouterStore<typeof routes>; 7 8export class RouterStore implements TInterfaceRouterStore { 9 constructor() { 10 makeAutoObservable(this); 11 } 12 13 routesHistory: TInterfaceRouterStore['routesHistory'] = []; 14 // we will load/hydrate initial route before the app is rendered, so "as any" is safe 15 currentRoute: TInterfaceRouterStore['currentRoute'] = {} as any; 16} 17 18export const routerStore = new RouterStore();
1import { redirectToGenerator } from 'dk-react-mobx-router'; 2import { addState } from 'dk-mobx-stateful-fn'; 3 4import { routes } from 'routes'; 5import { routerStore } from 'routerStore'; 6 7export const redirectTo = addState(redirectToGenerator({ 8 routes, 9 routerStore, 10 routeError500: routes.error500, 11}), 'redirectTo');
Or may be a part of RouterStore
.
1import { addState } from 'dk-mobx-stateful-fn'; 2 3export class RouterStore implements TInterfaceRouterStore { 4 constructor() { 5 makeAutoObservable(this, { redirectTo: false }); 6 } 7 8 routesHistory: TInterfaceRouterStore['routesHistory'] = []; 9 currentRoute: TInterfaceRouterStore['currentRoute'] = {} as any; 10 11 redirectTo = addState(redirectToGenerator({ 12 routes, 13 routerStore: this, 14 routeError500: routes.error500, 15 }), 'redirectTo'); 16}
routerStore.currentRoute
and render the relevant page component.1import { Router as RouterMobx } from 'dk-react-mobx-router'; 2import { observer } from 'mobx-react-lite'; 3 4import { routes } from 'routes'; 5import { routerStore } from 'routerStore'; 6 7// observer decorator is not necessary, it just gives "memo" 8export const Router = observer(() => { 9 return ( 10 <RouterMobx 11 routes={routes} 12 redirectTo={routerStore.redirectTo} 13 routerStore={routerStore} 14 /> 15 ); 16});
1import { getInitialRoute } from 'dk-react-mobx-router'; 2import { observer } from 'mobx-react-lite'; 3import { createRoot } from 'react-dom/client'; 4 5import { Router } from 'components/Router'; 6import { routes } from 'routes'; 7import { routerStore } from 'routerStore'; 8 9const App = observer(() => { 10 return ( 11 <> 12 <div className="menu"> 13 <div 14 onClick={() => routerStore.redirectTo({ route: 'home' })} 15 className={routerStore.currentRoute.name === 'home' ? 'active' : ''} 16 > 17 Home 18 </div> 19 <div 20 onClick={() => routerStore.redirectTo({ route: 'static' })} 21 className={routerStore.currentRoute.name === 'static' ? 'active' : ''} 22 > 23 Static 24 </div> 25 <div 26 onClick={() => routerStore.redirectTo({ route: 'dynamic', params: { foo: 'test', bar: 'smth' } })} 27 className={routerStore.currentRoute.name === 'dynamic' ? 'active' : ''} 28 > 29 Dynamic 30 </div> 31 </div> 32 <Router /> 33 </> 34 ); 35}); 36 37Promise.resolve() 38 // be sure to load an initial route 39 .then(() => routerStore.redirectTo(getInitialRoute({ 40 routes, 41 pathname: location.pathname + location.search, 42 fallback: 'error404' 43 }))) 44 .then(() => createRoot(document.getElementById('app')!).render(<App />));
The full code for this example (SPA without SSR version) is here. It is configured with code-splitting for every page, but it's easy to disable this function in the bundler config.
1import { createContext } from 'react'; 2import { hydrateRoot } from 'react-dom/client'; 3import { restoreState } from 'dk-mobx-restore-state'; 4import { loadComponentToConfig } from 'dk-react-mobx-router'; 5 6import { routes } from './routes'; 7import { RouterStore } from './routerStore'; 8 9// Create context 10 11const StoreContext = createContext(undefined as unknown as { routerStore: RouterStore }); 12 13const contextValue = { routerStore: new RouterStore() }; 14 15Promise.resolve() 16 // restore current route from Node server, no need to call 'location' 17 .then(() => restoreState({ target: contextValue, source: window.INITIAL_DATA })) 18 .then(() => { 19 // Load the async chunk for this page 20 const preloadedRouteName = Object.keys(routes).find( 21 (routeName) => contextValue.routerStore.currentRoute.name === routeName 22 ) as keyof typeof routes; 23 24 return loadComponentToConfig({ route: routes[preloadedRouteName] }); 25 }) 26 .then(() => 27 hydrateRoot( 28 document.getElementById('app')!, 29 <StoreContext.Provider value={contextValue}> 30 <App /> 31 </StoreContext.Provider> 32 ) 33 );
1const template500 = fs.readFileSync(path.resolve(__dirname, '../build/index.html'), 'utf-8'); 2 3const app = express() 4 .use(serveStatic(path.resolve(__dirname, '../build/public'))) 5 .get('*', async (req, res) => { 6 const contextValue = { routerStore: new RouterStore() }; 7 const reactApp = ( 8 <StoreContext.Provider value={contextValue}> 9 <App /> 10 </StoreContext.Provider> 11 ); 12 13 try { 14 await contextValue.routerStore.redirectTo( 15 getInitialRoute({ 16 routes, 17 pathname: req.originalUrl, 18 fallback: 'error404', 19 }) 20 ); 21 } catch (error: any) { 22 if (error.name === 'REDIRECT') { 23 res.redirect(error.message); 24 25 return; 26 } 27 28 console.error(error); 29 30 res.status(500).send(template500); 31 32 return; 33 } 34 35 const htmlMarkup = renderToString(reactApp); 36 const storeJS = JSON.parse(JSON.stringify(contextValue)); 37 38 res.send( 39 fs 40 .readFileSync(path.resolve(__dirname, '../build/public/index.html'), 'utf-8') 41 .replace(`<!-- HTML -->`, htmlMarkup) 42 .replace('<!-- INITIAL_DATA -->', JSON.stringify(escapeAllStrings(storeJS))) 43 ); 44 });
So, we only look at req.originalUrl
on the Node server and do not look at location
in the
Client code; we just restore the state from window.INITIAL_DATA
. The full example for SSR version
is here.
path (string) required
params (Record<string, (value: string) => boolean>) required if the path is dynamic
Should have a leading slash. It may be a constant value or a dynamic value with :param
syntax like
1{ 2 path: '/static' 3} 4 5{ 6 path: '/dynamic/:param1/:param2', 7 params: { 8 param1: (value: string) => value.length > 0, 9 param2: (value: string) => value === 'some', 10 }, 11}
When dynamic path is used - params
object with validators is necessary. Each validator should return
a boolean
value.
(async import) required
1{ 2 loader: () => import('./pages/home') 3} 4 5// @loadable/component should work, too 6import loadable from '@loadable/component'; 7 8{ 9 loader: loadable(() => import('./pages/home')) 10}
The imported file should have a default
export with a React Component. It may also export
pageName
, store
, actions
- this will be explained in other sections of this documentation.
(Record<string, any>) optional
1{ 2 error404: { 3 path: '/error404', 4 props: { errorCode: 404 }, 5 loader: () => import('./pages/error'), 6 }, 7 error500: { 8 path: '/error500', 9 props: { errorCode: 500 }, 10 loader: () => import('./pages/error'), 11 }, 12} 13 14const ErrorPage = observer((props: { errorCode: number }) => { 15 return `Error ${props.errorCode}`; 16});
These props
will be passed to the page component. In some cases it may be useful for
Dependency Injection (DI).
(Record<string, (value: string) => boolean>) optional
1{ 2 query: { 3 foo: (value: string) => value.length > 0, 4 } 5}
These parameters are always optional. So, if you go to http://site?bar=1
then routerStore.currentRoute.query
will be an empty object {}
. Only query params which are
described in the query
config will be present.
((config, ...args) => Promise<TypeRedirectToParams | void>) optional
config
argument is not perfectly TS-typed to avoid a circular dependency, so use the console to
check its contents
1{ 2 beforeEnter(config) { 3 /* 4 nextUrl: string; 5 nextRoute: any; 6 nextPathname: string; 7 nextQuery?: any; 8 nextSearch?: string; 9 10 currentUrl?: string; 11 currentQuery?: any; 12 currentRoute?: any; 13 currentSearch?: string; 14 currentPathname?: string; 15 */ 16 17 console.log(config); 18 19 if (config.nextRoute.name === 'query') { 20 return Promise.resolve({ route: 'dynamic', params: { foo: 'bar' }, query: { foo: 'bar' } }); 21 } 22 23 return Promise.resolve(); 24 } 25}
This method has the capability to redirect to another page, as shown in the example above.
You can also pass some arguments to this function by adding lifecycleParams
to the
redirectTo
function
1redirectTo = redirectToGenerator({ 2 routes, 3 routerStore: this, 4 routeError500: routes.error500, 5 lifecycleParams: [userStore] 6}); 7 8{ 9 beforeEnter(config, userStore) { 10 if (!userStore.isLoggedIn) { 11 return Promise.resolve({ route: 'login' }); 12 } 13 14 return Promise.resolve(); 15 } 16}
((config, ...args) => Promise<void> | Error<{ name: 'PREVENT_REDIRECT'} >) optional
config
argument is not perfectly TS-typed to avoid a circular dependency, so use the console to
check its contents
1{ 2 beforeLeave(config) { 3 /* 4 nextUrl: string; 5 nextRoute: any; 6 nextPathname: string; 7 nextQuery?: any; 8 nextSearch?: string; 9 10 currentUrl?: string; 11 currentQuery?: any; 12 currentRoute?: any; 13 currentSearch?: string; 14 currentPathname?: string; 15 */ 16 17 console.log(config); 18 19 if (config.nextRoute.name === 'query') { 20 throw Object.assign(new Error(''), { name: 'PREVENT_REDIRECT' }); 21 } 22 23 return Promise.resolve(); 24 } 25}
This method has the capability to prevent redirect, as shown in the example above.
You can also pass some arguments to this function by adding lifecycleParams
to the
redirectTo
function
1redirectTo = redirectToGenerator({ 2 routes, 3 routerStore: this, 4 routeError500: routes.error500, 5 lifecycleParams: [userStore] 6}); 7 8{ 9 beforeLeave(config, userStore) { 10 if (userStore.someFormNotFilled) { 11 const allowLeavePage = confirm('You form data will be lost, sure to go to another page?'); 12 13 if (!allowLeavePage) { 14 throw Object.assign(new Error(''), { name: 'PREVENT_REDIRECT' }); 15 } 16 } 17 18 return Promise.resolve(); 19 } 20}
routes (required) - config returned from createRouterConfig function
routerStore (required) - InterfaceRouterStore-compliant object
routeError500 (required) - route config for 500 error
lifecycleParams (optional) - Array<any>
This parameter is used to pass arguments to the
beforeEnter
and beforeLeave
methods. For example, you can pass lifecycleParams: [userStore]
to check if the user is logged in or has rights to view this page.
It can also be used for data-loading like
1redirectTo = redirectToGenerator({ 2 routes, 3 routerStore: this, 4 routeError500: routes.error500, 5 lifecycleParams: [apiStore] 6}); 7 8{ 9 beforeEnter(config, apiStore) { 10 return Promise.resolve() 11 .then(() => apiStore.getUser()) 12 .then(() => apiStore.getDashboard()) 13 .then(() => apiStore.getCart()) 14 .then(() => undefined) 15 } 16}
If you use the SPA (no SSR) approach, then you can use userStore
and apiStore
directly without
this dependency injection (DI), but for SSR websites, this is a powerful helper.
routes (required) - config returned from createRouterConfig function
routerStore (required) - InterfaceRouterStore-compliant object
redirectTo (required) - a function created with redirectToGenerator and addState
beforeMount (optional) - () => void
- this function is called only once on component mount
beforeSetPageComponent (optional) - (route) => void
- this function is called every time
before the render of any page. config
here is an extended route config
beforeUpdatePageComponent (optional) - () => void
- this function is called on every page update
before the render. Therefore, it will not be called for the first page render
1<RouterMobx 2 routes={routes} 3 redirectTo={routerStore.redirectTo} 4 routerStore={routerStore} 5 beforeMount={() => { 6 // component just mounted 7 }} 8 beforeSetPageComponent={(route) => { 9 // some page will be rendered soon 10 console.log(route); // shows which page will be loaded 11 }} 12 beforeUpdatePageComponent={() => { 13 // some new page will be rendered soon 14 // You may stop async actions and clear modular stores here 15 16 cancelExecutingApi(); 17 cancelExecutingActions(); 18 someStore.reset(); 19 }} 20/>
route (required) - a string representing some route
params (required if in route config) - Record<string, string>
query (optional) - Record<string, string>
noHistoryPush (optional) - if true, this redirect will not be present in the browser's history
This function is fully TypeScript-typed, and TypeScript hints will be shown for autocomplete.
1const routes = createRouterConfig({ 2 static: { 3 path: '/static', 4 loader: () => import('./pages/static'), 5 }, 6 dynamic: { 7 path: '/page/:foo', 8 params: { 9 foo: (value: string) => value.length > 0, 10 }, 11 query: { 12 q: (value: string) => value.length > 0, 13 }, 14 loader: () => import('./pages/dynamic'), 15 }, 16}); 17 18// Good 19redirectTo({ route: 'static' }) 20redirectTo({ route: 'dynamic', params: { foo: 'bar' } }) 21redirectTo({ route: 'dynamic', params: { foo: 'bar' }, query: { q: 's' } }) 22 23// TS errors 24redirectTo({ }); 25redirectTo({ route: 'nonExisting' }); 26redirectTo({ route: 'static', params: {} }); 27redirectTo({ route: 'dynamic' }); 28redirectTo({ route: 'dynamic', params: {} }); 29redirectTo({ route: 'dynamic', params: { a: 'b' } }); 30redirectTo({ route: 'dynamic', params: { foo: 'bar' }, query: { some: 'value' } });
redirectTo
function has a mobx reactive state because of
mobx-stateful-fn,
so we can utilize all of its capabilities.
1const GlobalHeader = observer(() => { 2 console.log(`Last redirect took ${routerStore.redirectTo.state.executionTime}ms`) 3 4 if (routerStore.redirectTo.state.isExecuting) { 5 return <Loader /> 6 } 7 8 return null; 9});
If you have problems with state is undefined
, do not forget to
exclude redirectTo
from makeAutoObservable
: makeAutoObservable(this, { redirectTo: false });
redirectTo
is an async function, so it's a good practice to handle errors
1redirectTo({ route: 'static' }).catch(error => console.error(error))
otherwise if some unexpected error happens in beforeEnter
/ beforeLeave
, you will get an
Uncaught exception.
This library fully supports unlimited redirects in SPA / SSR.
1const routes = createRouterConfig({ 2 one: { 3 path: '/1', 4 loader: () => import('./pages/one'), 5 }, 6 two: { 7 path: '/2', 8 loader: () => import('./pages/two'), 9 beforeEnter(config, userStore) { 10 if (!userStore.isLoggedIn) { 11 return Promise.resolve({ route: 'one' }); 12 } 13 14 return Promise.resolve(); 15 }, 16 }, 17 three: { 18 path: '/3', 19 loader: () => import('./pages/three'), 20 beforeEnter(config, userStore) { 21 if (!userStore.isLoggedIn) { 22 return Promise.resolve({ route: 'two' }); 23 } 24 25 return Promise.resolve(); 26 }, 27 }, 28 four: { 29 path: '/4', 30 loader: () => import('./pages/four'), 31 beforeEnter(config, userStore) { 32 if (!userStore.isLoggedIn) { 33 return Promise.resolve({ route: 'three' }); 34 } 35 36 return Promise.resolve(); 37 }, 38 }, 39}); 40 41redirectTo({ route: 'four' })
In this case if user goes to '/4' he will be redirected to '/3' then '/2' then '/1'. Browser's history
and routerStore.routesHistory
will only have ['/1']
. Also, chunks for pages four, three, two
will not be loaded.
routerStore.currentRoute
is a mobx-observable, so you can use it inside
autorun / reaction
, or within a component wrapped in observer
.
1import { TypeCurrentRoute } from 'dk-react-mobx-router'; 2import { routes } from 'routes'; 3 4const MyComponent = observer(() => { 5 const currentRoute = routerStore.currentRoute as TypeCurrentRoute<typeof routes.tabs>; 6 7 useEffect(() => { 8 const disposer = autorun(() => { 9 console.log(toJS(currentRoute.params)) 10 console.log(toJS(currentRoute.query)) 11 }) 12 13 return () => disposer(); 14 }, []); 15 16 if (currentRoute.params.tab === 'dashboard') { 17 return <Dashboard /> 18 } 19 20 if (currentRoute.params.tab === 'table') { 21 return <Table /> 22 } 23 24 return null; 25});
routerStore.currentRoute as TypeCurrentRoute<typeof routes.tabs>
here tells TS that we expect
the route to be 'routes.tabs' so its params
and query
will be TS-typed.
This feature should work, but this library does not have tests for this scenario yet.
@loadable/component
is used with SSR and allows loading page chunks in parallel with the
main chunk, improving the initial page loading speed. Here, only some differences from a regular
SSR configuration are highlighted.
Routes config:
1import loadable from '@loadable/component'; 2 3const routes = createRouterConfig({ 4 home: { 5 path: '/', 6 loader: loadable(() => import('./pages/home')), 7 } 8};
SSR side:
1import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server'; 2 3const webExtractor = new ChunkExtractor({ 4 statsFile: path.resolve(paths.build, 'web-loadable-stats.json'), 5 entrypoints: ['client'], 6}); 7 8const app = ( 9 <ChunkExtractorManager extractor={webExtractor}> 10 <StoreContext.Provider value={globals}> 11 <App /> 12 </StoreContext.Provider> 13 </ChunkExtractorManager> 14); 15 16const finalMarkup = template 17 .replace(`<!-- HTML -->`, htmlMarkup) 18 .replace( 19 '<!-- LINKS -->', 20 [webExtractor.getLinkTags(), webExtractor.getStyleTags()].join('\n') 21 ) 22 .replace('<!-- SCRIPTS -->', webExtractor.getScriptTags()) 23 .replace('<!-- INITIAL_DATA -->', JSON.stringify(escapeAllStrings(storeJS)));
Client side:
1import { loadableReady } from '@loadable/component'; 2 3Promise.resolve() 4 .then(() => loadableReady()) 5 // Still need to call loadComponentToConfig but this page's chunk will not be loaded twice, 6 // because it's already loaded 7 .then(() => { 8 const preloadedRouteName = Object.keys(routes).find( 9 (routeName) => contextValue.routerStore.currentRoute.name === routeName 10 ) as keyof typeof routes; 11 12 return loadComponentToConfig({ route: routes[preloadedRouteName] }); 13 }) 14 .then(() => 15 hydrateRoot( 16 document.getElementById('app')!, 17 <StoreContext.Provider value={contextValue}> 18 <App /> 19 </StoreContext.Provider> 20 ) 21 );
Router
will not rerender the page component if params
or query
have been changed.
However, if redirected to another route, the page component will be rerendered.
1const routes = createRouterConfig({ 2 home: { 3 path: '/', 4 loader: () => import('./pages/home'), 5 }, 6 static: { 7 path: '/static', 8 loader: () => import('./pages/home'), 9 } 10}; 11 12redirectTo({ route: 'home' }) 13 .then(() => redirectTo({ route: 'static' }))
Here we have the same component './pages/home'
, but different routes. Sometimes it's necessary
to prevent rerendering in this scenario. You may include in pages/home/index.ts
this code
1import { default as PageComponent } from './Home'; 2 3// This line 4export const pageName = 'home'; 5 6// Or if you have __dirname access you can use the folder's name 7export const pageName = __dirname.split('/').pop(); 8 9export default PageComponent;
This way the component will not be rerendered and the Router
will not call beforeSetPageComponent
or beforeUpdatePageComponent
. This is useful for the 'Modular stores / actions' section.
It's a good practice to split your stores / actions in MobX architectures by pages. This library has a built-in mechanism to do so.
Inside your page file, ex. pages/home/index.ts
, include relevant exports
1import { default as PageComponent } from './Home'; 2 3class HomeStore {} 4 5export const pageName = 'home'; 6 7// This line 8export const store = new HomeStore(); 9 10// And this 11export const actions = { 12 getData() { 13 return api.fetchData().then(data => { store.data = data }); 14 } 15} 16 17export default PageComponent;
Then in the Router
lifecycle, you may operate these variables like this:
1<Router 2 routes={routes} 3 redirectTo={routerStore.redirectTo} 4 routerStore={routerStore} 5 beforeSetPageComponent={(route: any) => { 6 if (!route.pageName) return; 7 8 if (route.store) { 9 globalStore.pages[route.pageName] = route.store; 10 } 11 12 if (route.actions) { 13 globalActions.pages[route.pageName] = route.actions; 14 } 15 }} 16 beforeUpdatePageComponent={() => { 17 globalStore.pages = {}; 18 globalActions.pages = {}; 19 }} 20/>
You may operate route.store
and route.actions
according to your architecture; this library
simply provides a way to separate them inside the page's async chunks and initialize them
when the page is loaded.
This library uses history.js, and it is exported
for some custom scenarios. Be aware that in SSR (Node.js server code) history
is null
.
1import { history } from 'dk-react-mobx-router'; 2 3if (typeof window !== 'undefined') { 4 history.listen((params) => { 5 // some logic 6 }); 7 8 history.back(); 9}
There are no plans to implement it. Use history.listen
to track the hash and synchronize it with
your own mobx-store parameter (may be a part of the routerStore
).
dk-mobx-stateful-fn
is necessary for the Router
. redirectTo
is an async function, so we have
to track when it has finished before rendering the page component.
However, this does not prevent you from using custom logic inside your redirect function. For example, if you want to scroll the page to the top on every redirect, you may use this:
1import { TypeRedirectToParams } from 'dk-react-mobx-router'; 2import { TypeFnState } from 'dk-mobx-stateful-fn'; 3import { routes } from 'routes'; 4 5type TypeCustomRedirectTo = (<TRouteName extends keyof typeof routes>( 6 params: TypeRedirectToParams<typeof routes, TRouteName> 7) => Promise<void>) & 8 TypeFnState; 9 10export class RouterStore implements TInterfaceRouterStore { 11 redirectTo: TypeCustomRedirectTo = addState((params) => { 12 if (typeof window !== 'undefined') { 13 window.scroll(0, 0); 14 } 15 16 return redirectToGenerator({ 17 routes, 18 routerStore: this, 19 routeError500: routes.error500, 20 })(params); 21 }, 'redirectTo'); 22}
It is a bit tricky to construct TypeCustomRedirectTo
, but it's helpful in some cases.
Usually the Router
's lifecycle, like beforeSetPageComponent
, should be sufficient for most cases.
No vulnerabilities found.
No security vulnerabilities found.