The <Resource> component

<Resource> components define the CRUD routes of a react-admin application.

In react-admin terms, a resource is a string that refers to an entity type (like ‘products’, ‘subscribers’, or ‘tags’). Records are objects with an id field, and two records of the same resource have the same field structure (e.g. all posts records have a title, a publication date, etc.).

A <Resource> component has 3 responsibilities:

  • It defines the components for the CRUD routes of a given resource (to display a list of records, the details of a record, or to create a new one).
  • It creates a context that lets every descendant component know the current resource name (this context is called ResourceContext).
  • It stores the resource definition (its name, icon, and label) inside a shared context (this context is called ResourceDefinitionContext).

<Resource> components can only be used as children of the <Admin> component.

Basic Usage

For instance, the following admin app offers an interface to the resources exposed by the JSONPlaceholder API (posts, users, comments, and tags):

import * as React from "react";
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';

import { PostList, PostCreate, PostEdit, PostShow, PostIcon } from './posts';
import { UserList } from './posts';
import { CommentList, CommentEdit, CommentCreate, CommentIcon } from './comments';

const App = () => (
    <Admin dataProvider={jsonServerProvider('https://jsonplaceholder.typicode.com')}>
        {/* complete CRUD pages for posts */}
        <Resource name="posts" list={PostList} create={PostCreate} edit={PostEdit} show={PostShow} />
        {/* read-only user list */}
        <Resource name="users" list={UserList} />
        {/* no show page for the comments resource */}
        <Resource name="comments" list={CommentList} create={CommentCreate} edit={CommentEdit} icon={CommentIcon} />
    </Admin>
);

The routes call the following dataProvider methods:

  • list calls getList() on mount
  • show calls getOne() on mount
  • edit calls getOne() on mount, and update() or delete() on submission
  • create calls create() on submission

Tip: Which API endpoint does a resource rely on? The <Resource> component doesn’t know this mapping - it’s the dataProvider’s job to define it.

name

name is the only required prop for a <Resource>. React-admin uses the name prop both to determine the API endpoint (passed to the dataProvider), and to form the URL for the resource.

<Resource name="posts" list={PostList} create={PostCreate} edit={PostEdit} show={PostShow} />

For this resource react-admin will fetch the https://jsonplaceholder.typicode.com/posts endpoint for data.

The routing will map the component as follows:

  • /posts/ maps to PostList
  • /posts/create maps to PostCreate
  • /posts/:id maps to PostEdit
  • /posts/:id/show maps to PostShow

Tip: If you want to use a special API endpoint (e.g. ‘https://jsonplaceholder.typicode.com/my-custom-posts-endpoint’) without altering the URL in the react-admin application (so still use /posts), write the mapping from the resource name (posts) to the API endpoint (my-custom-posts-endpoint) in your own dataProvider.

list, create, edit, show

<Resource> allows you to define a component for each CRUD operation, using the following prop names:

Tip: Under the hood, the <Resource> component uses react-router to create several routes:

  • / maps to the list component
  • /create maps to the create component
  • /:id maps to the edit component
  • /:id/show maps to the show component

<Resource> also accepts additional props:

icon

React-admin will render the icon prop component in the menu:

// in src/App.js
import * as React from "react";
import PostIcon from '@mui/icons-material/Book';
import UserIcon from '@mui/icons-material/People';
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';

import { PostList } from './posts';

const App = () => (
    <Admin dataProvider={jsonServerProvider('https://jsonplaceholder.typicode.com')}>
        <Resource name="posts" list={PostList} icon={PostIcon} />
        <Resource name="users" list={UserList} icon={UserIcon} />
    </Admin>
);

options

options.label allows to customize the display name of a given resource in the menu.

<Resource name="v2/posts" options={{ label: 'Posts' }} list={PostList} />

recordRepresentation

Whenever react-admin needs to render a record (e.g. in the title of an edition view, or in a <ReferenceField>), it uses the recordRepresentation to do it. By default, the representation of a record is its id field. But you can customize it by specifying the representation you want.

For instance, to change the default representation of “users” records to render the full name instead of the id:

<Resource
    name="users"
    list={UserList}
    recordRepresentation={(record) => `${record.first_name} ${record.last_name}`}
/>

recordRepresentation can take 3 types of values:

  • a string (e.g. 'title') to specify the field to use as representation
  • a function (e.g. (record) => record.title) to specify a custom string representation
  • a React component (e.g. <MyCustomRecordRepresentation />). In such components, use useRecordContext to access the record.

Resource Context

<Resource> also creates a ResourceContext, that gives access to the current resource name to all descendants of the main page components (list, create, edit, show).

To read the current resource name, use the useResourceContext() hook.

For instance, the following component displays the name of the current resource:

import * as React from 'react';
import { Datagrid, DateField, TextField, List, useResourceContext } from 'react-admin';

const ResourceName = () => {
    const resource = useResourceContext();
    return <>{resource}</>;
}

const PostList = () => (
    <List>
        <>
            <ResourceName /> {/* renders 'posts' */}
            <Datagrid>
                <TextField source="title" />
                <DateField source="published_at" />
            </Datagrid>
        </>
    </List>
)

Tip: You can change the current resource context, e.g. to use a component for a related resource. Use the <ResourceContextProvider> component for that:

const MyComponent = () => (
    <ResourceContextProvider value="comments">
        <ResourceName /> {/* renders 'comments' */}
        ...
    </ResourceContextProvider>
);