Skip to main content
👀 Interested in the latest enterprise backend features of refine? 👉 Join now and get early access!
Version: 4.xx.xx

1. Adding List Page

In Unit 2.4, we created the CRUD pages automatically with Inferencer, and now we will do it manually by using the code generated by Inferencer to customize those pages freely.

Creating the list page​

First, we need to create our file, named list.tsx, under the src/pages/blog-posts folder. We will then copy the list page code generated by Inferencer and paste it into the file; for this, follow these steps:

  1. Navigate to localhost:3000/blog-posts in your browser.

  2. Click on the "Show Code" button in the bottom right corner of the page.

  3. You will see the list page code that was generated by Inferencer. Copy it by clicking on the "Copy" button.

  4. Paste the code into the newly created list.tsx file.

You can see an example list page generated by Inferencer below:

localhost:3000/blog-posts

Understanding the List Component​

Hooks and Components in List Page​

  • The useTable hook is used for fetching data and managing the table state. It is imported from the @refinedev/react-table package, which combines the functionality of the TanStack Table v8 package and the useTable hook from the @refinedev/core package, providing the features of both.

    For more information, refer to the useTable documentation and the TanStack Table v8 documentation→

  • The useNavigation hook is used for navigating between pages. In this case, we are using it to navigate to the edit and show pages when the user clicks on their respective buttons in the table.

    For more information, refer to the useNavigation documentation →

Handling Relationships​

Each blog post includes the category field, which has an id property. This is a foreign key that points to the categories resource, which is different from the blog_posts resource.

There is a title field in the categories resource; to display it in the table, we can use the useMany hook provided by refine.

This hook allows us to fetch data for multiple records in a single request by providing the id's of the related records. In this case, we need to provide the id's of the blog posts categories. It is particularly useful when we need to fetch related data for multiple records.

In the code below, each blog post record has a category field:

https://api.fake-rest.refine.dev/blog_posts
{
...
"category": {
"id": 1
}
...
},
{
...
"category": {
"id": 2
}
...
}

We can use the useMany hook to fetch the full category records for each of these blog posts like this:

import { useMany } from "@refinedev/core";

const { data } = useMany({
resource: "categories",
ids: blogPosts.map((blogPost) => blogPost.category.id),
});

This will pass the resource and ids to the dataProvider's getMany function. The dataProvider will then make a single request to the API to fetch the full records for each category related to the blog posts. The resulting data variable will be an array of category records, like this:

[
{
id: 1,
title: "mock category title",
},
{
id: 2,
title: "another mock category title",
},
];

We can then use this data array to display the title of each category in the table.

For more information, refer to the useMany documentation→

Adding the List Page to the App​

Now that we have created the list page, we can add it to the App.tsx file:

  1. Open src/App.tsx file on your editor.

  2. Import the created BlogPostList component.

  3. Replace the HeadlessInferencer component with the BlogPostList component.

src/App.tsx
import { Refine } from "@refinedev/core";
import { HeadlessInferencer } from "@refinedev/inferencer/headless";
import routerBindings, { NavigateToResource } from "@refinedev/react-router-v6";
import dataProvider from "@refinedev/simple-rest";
import { BrowserRouter, Route, Routes, Outlet } from "react-router-dom";

import { BlogPostList } from "pages/blog-posts/list";

import { Layout } from "components/layout";

import "./App.css";

const App = () => {
return (
<BrowserRouter>
<Refine
routerProvider={routerBindings}
dataProvider={dataProvider("https://api.fake-rest.refine.dev")}
resources={[
{
name: "blog_posts",
list: "/blog-posts",
show: "/blog-posts/show/:id",
create: "/blog-posts/create",
edit: "/blog-posts/edit/:id",
},
]}
>
<Routes>
<Route
element={
<Layout>
<Outlet />
</Layout>
}
>
<Route
index
element={
<NavigateToResource resource="blog_posts" />
}
/>

<Route path="blog-posts">
<Route index element={<BlogPostList />} />
<Route
path="show/:id"
element={<HeadlessInferencer />}
/>
<Route
path="edit/:id"
element={<HeadlessInferencer />}
/>
<Route
path="create"
element={<HeadlessInferencer />}
/>
</Route>

<Route path="*" element={<div>Error!</div>} />
</Route>
</Routes>
</Refine>
</BrowserRouter>
);
};
export default App;

Now, we can see the list page in the browser at localhost:3000/blog-posts


Checklist