Skip to main content
Version: 4.xx.xx

1. Adding List Page

In Unit 2.4, we created the CRUD pages automatically with Inferencer. In this unit, we will create the CRUD pages manually using the codes generated by Inferencer. So, you can customize the pages as you wish.

Creating List Page

First, let's create our file under the src/pages/blog-posts folder. We will name it list.tsx. Then, we will copy the list page code generated by Inferencer and paste it into the file.

To copy the code and paste it into the file, follow the steps below:

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

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

  3. You can see the list page code generated by Inferencer. Click on the "Copy" button to copy the code.

  4. Paste the code into the you created, list.tsx file.

You can see the list page code generated by Inferencer below:

http://localhost:3000
setInitialRoutes(['/blog-posts'])

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 } from 'react-router-dom'

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 index element={<NavigateToResource resource="blog_posts" />} />

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

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

render(<App />)

Instead of coding the list page component from scratch, Inferencer created the required code base on API response, so that we can customize.

Understanding the List Component

We will go through the list page hooks one by one.

Handling Relationships

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

There is a title field In the categories resource. To display the category title 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.

Refer to the useMany documentation for more information &#8594

In this tutorial, each blog post record has a category field as below:

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.

Adding the List Page to the App

Now that we have created the list page, we need to 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 } from 'react-router-dom'

import { BlogPostList } from 'pages/blog-posts/list'

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 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>} />
</Routes>
</Refine>
</BrowserRouter>
)
}
export default App

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



Checklist