react-static-routing v2.0.1
Info
Install and Initialize
To install, use below code
npm install react-static-routingOr
yarn add react-static-routingAfter installation, use the following code to create static router objects. In this example, using createRoutes
function is optional. It is used for type checking and code intellisense for each value in routes.
import {createRoutes, createStaticRouter} from "react-static-routing";
routes = createRoutes({ // `routes` is a key-value-pair object
homePage: {
path: '/',
component: HomePage,
exact: true
},
loggedInPage: {
path: '/login',
component: LogInPage,
exact: true,
condition: () => !hasToken() // hide route if condition is not true
},
notLoggedInHomePage: {
path: '/',
component: LogInPage,
exact: true,
condition: () => !hasToken(),
fallbackKey: 'homePage' // if `condition` return is false, redirect to `homePage` route (meaning '/' for this example)
},
asyncRoute: {
path: '/async',
asyncComponent: () => import('./AsyncPage'), // for spliting budle for this route.
exact: true,
}
})
const {router, useRouteInfo, RouterView, history} = createStaticRouter(routes, options);Then we should add RouterView in react root component :
function App() {
return <>
<RouterView NotFoundPage={NotFoundPage}> {/* children for this component is optional */}
{(page: React.ReactNode) => page}
</RouterView>
</>
}
render(<App/>, document.getElementById("root"));Now we are able to use router for redirecting between pages with static error checking!
// in our react components :
router.homePage.toPush() // redirect to homePage route.
router.notExistingPage.toPush() // we get error, because we didn't add `notExistingPage` to `routes` object.history is exactly history object for the npm package history@4.10.1.
- Please Note!!! For any redirection just use
routerand thishistoryobject and never create any other history object. Because we subscribed to events of thehistoryobject. Or if you have history object (just version 4), you should pass it tocreateStaticRoutersecond argument.
useRouteInfo is a hook to get route values in page component. For more information about useRouteInfo, please see
Passing-Parameters paragraph.
How it works
Static routing is created to prevent some bug in routes or route change, and alert them in compile time.
Conditions
if we want some routes to have some conditions, we should add a condition property to remove the route if we pass
false. In the following example, if user is logged-in (has token!), user will see home page, otherwise, the user sees
login page. Because if condition function returns false, we do not add the route to RouterView.
const routes = {
//...
homePage: {
path: '/',
component: HomePage,
exact: true,
condition: () => Boolean(token) // for example here, we want to check if user is logged-in or not (via token)
},
loggedInPage: {
path: '/',
component: LogInPage,
exact: true,
}
//...
};Fallbacks for conditions
If we want to redirect page, when condition function returns false, we can use fallback or fallbackKey.
fallback is direct url, see the following example :
const routes = {
//...
homePage: {
path: '/',
component: HomePage,
exact: true,
condition: () => Boolean(token), // for example here, we want to check if user is logged-in or not (via token).
fallback: '/login' // if condition is `false`, redirect to login url.
},
//...
};If we want to redirect to an url existing to route object, we'd better use fallbackKey.
const routes = {
//...
homePage: {
path: '/',
component: HomePage,
exact: true,
condition: () => Boolean(token), // for example here, we want to check if user is logged-in or not (via token).
fallbackKey: 'loggedInPage' // redirect to `loggedInPage` route, which exist in `routes` object.
},
// ...
loggedInPage: {
path: '/login',
component: LogInPage,
exact: true,
},
//...
};Passing Parameters
For every route, we can add query and params parameters as follows:
const routes = {
//...
fundBuyOrSell: {
path: '/fund/:id',
component: FundBuyOrSellPage,
exact: true,
params: {} as {
id: number,
name?: string // this param is optional
},
query: {hamburger: false} as {
hamburger: boolean,
id?: number // this query param is optional
},
state: {} as {
caller: string
}
},
//...
};In this example we have id parameter as params in url, hamburger query parameter, and caller for state in
history. Now we are able to redirect to them as follows:
- Use
toPushto redirect the route without replacing. - Use
toReplaceto redirect the route with replacing on the current history location. - Use
toBackFromHistoryto go back until the route with the parameters you passed. If the route exist in the history, it will redirect and returns true, otherwise, just return false and does nothing else.
const parameters = {
params: {id: 123},
query: {hamburger: true},
state: {caller: 'fundPage'},
};
router.fundBuyOrSell.toPush(parameters);
// OR
router.fundBuyOrSell.toReplace(parameters); //to replace instead of push.
router.fundBuyOrSell.toPush({params: {ids: '123'}}); // throws error! because `ids` is not defined!
router.fundBuyOrSell.toPush({params: {id: 123}}); // throws error! because `query` and `state` are defined in `routes` but we didn't add them in `toPush` arguments object.
router.fundBuyOrSell.toBackFromHistory(parameters); // goes back to the route `fundOrSell` in the browser history, with the passed parameres.Use static values in our page components
In a page, if you want to reach this parameter, you can get them as follows:
const {params, query, state, hasReturned, queryKeys} = useRouteInfo('payment');
console.log(params.id); // logs: 123
console.log(query.hamburger); // logs: true
console.log(state.caller); // logs: fundPage
console.log(params.idd); // compile time error! because `idd` does not exist in params.
console.log(hasReturned); // Shows weather we have pushed back button or returning back to this route or not,
// `false` means we have used `toPush` or `toReplace` methods, `true` means we have used `history.back` or `toBackFromHistory` method.
console.log(queryKeys); // logs: {hamburger: 'hamburger'}, gives you an object like {[queryName]:queryName}
// remember if you want to use `queryKeys` you should add `query` property for the route like ↓
// {
// ...
// query: `{hamburger: false}`
// ...
// }
// because JavaScript code will give you the returning object and TypeScript doesn'tAppRouteType
routes object should be as a AppRouteType as we shown in the following code.
type AppRouteType = {
path: string; // path of the route
condition?: (() => boolean); // condition. See ##Conditions paragraph.
fallback?: string; // if condition returns false, which route should we be redirected to? See ##Conditions paragraph
fallbackKey?: string; // to use route key instead of `fallback` value. See ##Conditions paragraph
component: React.ComponentType; // the route/page component
query?: { [key: string]: unknown }; // parsed query string passed to the page/route
params?: { [key: string]: unknown };// params passed to the page/route, which will be replace in query
state?: { [key: string]: unknown };
};Rerender of RouterView
If you want to make RouterView rerender, you can add useHook property as shown in the following example ↓
function useCustomHook() {
useTokenChange();
useEnvironmentChange();
useWebsocketConnectionChange();
}
<RouterView NotFoundPage={NotFoundPage} useHooks={useCustomHook}/>
// or instead you can add it to options for `createStaticRouter` ↓
const {router, useRouteInfo, RouterView} = createStaticRouter(routes, {useRouteViewHook: useToken});