Router Provider
refine needs some router functions to create resource pages, navigate, etc. This provider allows you to use the router library you want.
A router provider must include the following methods:
const routerProvider = {
useHistory: () => {
push: (...args) => any,
replace: (...args) => any,
goBack: (...args) => any,
},
useLocation: () => {
pathname: string,
search: string,
},
useParams: <Params extends { [K in keyof Params]?: string } = {}>() => Params,
Prompt: React.FC<PromptProps*>,
Link: React.FC<any>,
RouterComponent?: React.FC<any>,
};
*
: Too see →<PromptProps>
refine includes many out-of-the-box router providers to use in your projects like
We do not recommend creating this provider unless you do not need any customization on the router. Instead, you can use Next.js Router for your Next.js app and React Router or React Location for your react app.
Usage
To activate router provider in refine, we have to pass the routerProvider
to the <Refine />
component.
- React Router
- React Location
- Next.js Router
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-react-router";
const App: React.FC = () => {
return <Refine routerProvider={routerProvider} />;
};
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-react-location";
const App: React.FC = () => {
return <Refine routerProvider={routerProvider} />;
};
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-nextjs-router";
const App: React.FC = () => {
return <Refine routerProvider={routerProvider} />;
};
Creating a router provider
The routerProvider
methods refine expects are exactly the same as react-router-dom methods.
To understand how to create a routerProvider
, let's examine how the React Router, React Location and Next.js Router libraries provided by refine create a routerProvider
.
useHistory
refine uses push
, replace
, and goBack
functions of useHistory
for navigation.
- React Router
- React Location
- Next.js Router
import { IRouterProvider } from "@pankod/refine";
import { useHistory } from "react-router-dom";
const routerProvider: IRouterProvider = {
...
useHistory,
...
};
import { IRouterProvider } from "@pankod/refine";
import { useHistory, useLocation } from "react-location";
const routerProvider: IRouterProvider = {
...
useHistory: () => {
const navigate = useNavigate();
const location = useLocation();
return {
push: (path: string) => {
navigate({
to: path,
});
},
replace: (path: string) => {
navigate({
to: path,
replace: true,
});
},
goBack: () => {
location.history.back();
},
};
},
...
};
import { IRouterProvider } from "@pankod/refine";
import { useRouter } from "next/router";
const routerProvider: IRouterProvider = {
...
useHistory: () => {
const router = useRouter();
const { push, replace, back } = router;
return {
push,
replace,
goBack: back,
};
},
...
};
useLocation
refine uses the pathname
to find the location of the user and search
to find the query string.
- React Router
- React Location
- Next.js Router
import { IRouterProvider } from "@pankod/refine";
import { useLocation } from "react-router-dom";
const routerProvider: IRouterProvider = {
...
useLocation,
...
};
import { IRouterProvider } from "@pankod/refine";
import { useLocation } from "react-location";
const routerProvider: IRouterProvider = {
...
useLocation: () => {
const location = useLocation();
return {
pathname: location.current.pathname,
search: location.current.searchStr,
};
},
...
};
import { IRouterProvider } from "@pankod/refine";
import { useRouter } from "next/router";
import qs from "qs";
const routerProvider: IRouterProvider = {
...
useLocation: () => {
const router = useRouter();
const { pathname, query } = router;
const queryParams = qs.stringify(query);
return {
pathname,
search: queryParams && `?${queryParams}`,
};
},
...
};
useParams
refine uses useParams
to use action name, record id, etc. found in the route.
- React Router
- React Location
- Next.js Router
import { IRouterProvider } from "@pankod/refine";
import { useParams } from "react-router-dom";
const routerProvider: IRouterProvider = {
...
useParams,
...
};
import { IRouterProvider } from "@pankod/refine";
import { useMatch } from "react-location";
const routerProvider: IRouterProvider = {
...
useParams: () => {
const { params } = useMatch();
return params as any;
},
...
};
import { IRouterProvider } from "@pankod/refine";
import { useRouter } from "next/router";
const routerProvider: IRouterProvider = {
...
useParams: <Params>() => {
const router = useRouter();
const { query } = router;
return query as unknown as Params;
},
...
};
Prompt
refine uses <Prompt>
to display the alert when warnWhenUnsavedChanges is true
.
- React Router
- React Location
- Next.js Router
import { IRouterProvider } from "@pankod/refine";
import { Prompt } from "react-router-dom";
const routerProvider: IRouterProvider = {
...
Prompt: Prompt as any,
...
};
import { useEffect } from "react";
import { useLocation } from "react-location";
import type { PromptProps } from "@pankod/refine";
export const Prompt: React.FC<PromptProps> = ({
message,
when,
setWarnWhen,
}) => {
const location = useLocation();
useEffect(() => {
if (!when) return;
const unblock = location.history.block((transition) => {
if (window.confirm(message)) {
setWarnWhen?.(false);
unblock();
transition.retry();
} else {
location.current.pathname = window.location.pathname;
}
});
return unblock;
}, [when, location, message]);
return null;
};
import { IRouterProvider } from "@pankod/refine";
import { Prompt } from "./prompt";
const routerProvider: IRouterProvider = {
...
Prompt,
...
};
import { useRouter } from "next/router";
import { useEffect } from "react";
import type { PromptProps } from "@pankod/refine";
export const Prompt: React.FC<PromptProps> = ({
message,
when,
setWarnWhen,
}) => {
const router = useRouter();
useEffect(() => {
const routeChangeStart = () => {
if (when) {
const allowTransition = window.confirm(message);
if (allowTransition) {
setWarnWhen?.(false);
} else {
router.events.emit("routeChangeError");
throw "Abort route change due to unsaved changes prompt. Ignore this error.";
}
}
};
router.events.on("routeChangeStart", routeChangeStart);
return () => router.events.off("routeChangeStart", routeChangeStart);
}, [when]);
return null;
};
import { IRouterProvider } from "@pankod/refine";
import { Prompt } from "./prompt";
const routerProvider: IRouterProvider = {
...
Prompt,
...
};
Link
refine uses <Link>
for navigation.
- React Router
- React Location
- Next.js Router
import { IRouterProvider } from "@pankod/refine";
import { Link } from "react-router-dom";
const routerProvider: IRouterProvider = {
...
Link,
...
};
import { IRouterProvider } from "@pankod/refine";
import { Link } from "react-location";
const routerProvider: IRouterProvider = {
...
Link,
...
};
import { IRouterProvider } from "@pankod/refine";
import { Link } from "next/link";
const routerProvider: IRouterProvider = {
...
Link,
...
};
routes
routes
allow us to create custom pages in your react apps that have different paths than those defined by resources
.
Refer to the Custom Pages documentation for detailed information. →
Since Nextjs has a file system based router built on the page concept, you can create your custom pages under the pages folder you don't need routes
property.
RouterComponent
It creates the navigation routes of the refine app and determines how the components will be rendered on which paths.
In general, we can list what it does as follows:
- It creates create, edit, list, show pages with paths according to the resources' own name.
- Allows rendering of custom
routes
passed torouterProviders
as properties. - Different routes render when the user is authenticated and not.
RouterComponent
is required for refine React apps but not required for Nextjs apps.
Since Nextjs has a folder base route structure, it is used by exporting the <NextRouteComponent>
from the created page.
→ Refer to the React Router's <RouterComponent>
for detailed usage information.
→ Refer to the React Location's <RouterComponent>
for detailed usage information.
→ Refer to the Next.js Router's <NextRouteComponent>
for detailed usage information.
Serving the application from a subdirectory
- React Router
- React Location
- Next.js
If you want to serve from a subdirectory in your refine react app. You can use basepath
property of <Router>
.
The <RouterComponent>
in the react-router package passes all its properties to the <BrowserRouter>
component. Therefore, a <BrowserRouter>
property that we will give to the <RouterComponent>
is passed to the <BrowserRouter>
that wraps our application.
In the example below you can see how to serve the application in a subdirectory.
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-react-router";
import dataProvider from "@pankod/refine-simple-rest";
import "@pankod/refine/dist/styles.min.css";
import { PostList, PostCreate, PostEdit, PostShow } from "pages/posts";
const API_URL = "https://api.fake-rest.refine.dev";
const { RouterComponent } = routerProvider;
const CustomRouterComponent = () => <RouterComponent basename="/admin" />;
const App: React.FC = () => {
return (
<Refine
routerProvider={{
...routerProvider,
RouterComponent: CustomRouterComponent,
}}
dataProvider={dataProvider(API_URL)}
resources={[
{
name: "posts",
list: PostList,
create: PostCreate,
edit: PostEdit,
show: PostShow,
},
]}
/>
);
};
export default App;
Now you can access our application at www.domain.com/admin
.
If you want to serve from a subdirectory in your refine react app. You can use basename
property of <Router>
.
The <RouterComponent>
in the react-location package passes all its properties to the <Router>
component. Therefore, a <Router>
property that we will give to the <RouterComponent>
is passed to the <Router>
that wraps our application.
In the example below you can see how to serve the application in a subdirectory.
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-react-location";
import dataProvider from "@pankod/refine-simple-rest";
import "@pankod/refine/dist/styles.min.css";
import { PostList, PostCreate, PostEdit, PostShow } from "pages/posts";
const API_URL = "https://api.fake-rest.refine.dev";
const { RouterComponent, location } = routerProvider;
const CustomRouterComponent = () => (
<RouterComponent location={location} basepath="/admin" />
);
const App: React.FC = () => {
return (
<Refine
routerProvider={{
...routerProvider,
RouterComponent: CustomRouterComponent,
}}
dataProvider={dataProvider(API_URL)}
resources={[
{
name: "posts",
list: PostList,
create: PostCreate,
edit: PostEdit,
show: PostShow,
},
]}
/>
);
};
export default App;
Now you can access our application at www.domain.com/admin
.
To serve your application from a subdirectory in your refine Nextjs application, simply add basePath
to your next.config.js
file.
module.exports = {
basePath: "/admin",
};
Refer to the Nextjs
documentation for detailed usage information. →
Now you can access our application at www.domain.com/admin
.