Navigation
Now we've set up our routes and resources. In this step, we'll be learning about Refine's navigation helpers and how to use them in our app.
You can always use the preferred methods of your routing library to navigate between pages. Refine's navigation hooks are helpers to make it easier to navigate between any action of any resource.
We'll use the useNavigation
hook and create buttons to navigate to the create, edit and show pages of the products. Additionally we'll provide a link to the list page of the products in the <Header />
component.
Adding a Link to the List Page and to the Create Page
We'll be using the useNavigation
hook from @refinedev/core
and the <Link />
component of the react-router
library to create links to the list page and the create page of the products.
Let's update our <Header />
component and add a link to the list page of the products:
import React from "react";
import { useLogout, useGetIdentity, useNavigation } from "@refinedev/core";
import { Link } from "react-router";
export const Header = () => {
const { mutate, isLoading } = useLogout();
const { data: identity } = useGetIdentity();
// You can also use methods like list or create to trigger navigation.
// We're using url methods to provide more semantically correct html.
const { listUrl, createUrl } = useNavigation();
return (
<>
<h2>
<span>Welcome, </span>
<span>{identity?.name ?? ""}</span>
</h2>
<Link to={listUrl("protected-products")}>List Products</Link>
<Link to={createUrl("protected-products")}>Create Product</Link>
<button type="button" disabled={isLoading} onClick={mutate}>
Logout
</button>
</>
);
};
Adding Show and Edit Buttons to the List Page
Similarly, we'll update the <ListProducts />
component and add links for showing and editing the products.
import { useTable, useMany, useNavigation } from "@refinedev/core";
import { Link } from "react-router";
export const ListProducts = () => {
const {
tableQuery: { data, isLoading },
current,
setCurrent,
pageCount,
sorters,
setSorters,
} = useTable({
resource: "protected-products",
pagination: { current: 1, pageSize: 10 },
sorters: { initial: [{ field: "id", order: "asc" }] },
});
// You can also use methods like show or list to trigger navigation.
// We're using url methods to provide more semantically correct html.
const { showUrl, editUrl } = useNavigation();
/* ... */
return (
<div>
<h1>Products</h1>
<table>
<thead>
<tr>
<th onClick={() => onSort("id")}>
ID {indicator[getSorter("id")]}
</th>
<th onClick={() => onSort("name")}>
Name {indicator[getSorter("name")]}
</th>
<th>Category</th>
<th onClick={() => onSort("material")}>
Material {indicator[getSorter("material")]}
</th>
<th onClick={() => onSort("price")}>
Price {indicator[getSorter("price")]}
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{data?.data?.map((product) => (
<tr key={product.id}>
<td>{product.id}</td>
<td>{product.name}</td>
<td>
{
categories?.data?.find(
(category) => category.id == product.category?.id,
)?.title
}
</td>
<td>{product.material}</td>
<td>{product.price}</td>
<td>
<Link to={showUrl("protected-products", product.id)}>Show</Link>
<Link to={editUrl("protected-products", product.id)}>Edit</Link>
</td>
</tr>
))}
</tbody>
</table>
<div className="pagination">{/* ... */}</div>
</div>
);
};
You can also use anchors and any other navigation methods provided by your routing library to move between pages, without being limited to the useNavigation
hook.
Now we've learned about the navigating between pages with Refine's useNavigation
hook. In the next step, we'll be updating our components to benefit from the parameter inference of Refine.
import { Refine, Authenticated } from "@refinedev/core"; import routerProvider, { NavigateToResource } from "@refinedev/react-router"; import { BrowserRouter, Routes, Route, Outlet } from "react-router"; import { dataProvider } from "./providers/data-provider"; import { authProvider } from "./providers/auth-provider"; import { ShowProduct } from "./pages/products/show"; import { EditProduct } from "./pages/products/edit"; import { ListProducts } from "./pages/products/list"; import { CreateProduct } from "./pages/products/create"; import { Login } from "./pages/login"; import { Header } from "./components/header"; export default function App(): JSX.Element { return ( <BrowserRouter> <Refine dataProvider={dataProvider} authProvider={authProvider} routerProvider={routerProvider} resources={[ { name: "protected-products", list: "/products", show: "/products/:id", edit: "/products/:id/edit", create: "/products/create", meta: { label: "Products" }, } ]} > <Routes> <Route element={( <Authenticated key="authenticated-routes" redirectOnFail="/login"> <Header /> <Outlet /> </Authenticated> )} > <Route index element={<NavigateToResource resource="protected-products" />} /> <Route path="/products"> <Route index element={<ListProducts />} /> <Route path=":id" element={<ShowProduct />} /> <Route path=":id/edit" element={<EditProduct />} /> <Route path="create" element={<CreateProduct />} /> </Route> </Route> <Route element={( <Authenticated key="auth-pages" fallback={<Outlet />}> <NavigateToResource resource="protected-products" /> </Authenticated> )} > <Route path="/login" element={<Login />} /> </Route> </Routes> </Refine> </BrowserRouter> ); }