Tutorial

How To Create Admin Interfaces in React with react-admin

React

Introduction

Applications exposing an API will often need an administrator (admin) page to view and edit the data behind the application. Creating one usually requires the painstaking process of building an interface, followed by manually handling every request to GET or POST data to and from the API.

react-admin reduces this drudgery by automatically consuming your (REST, GraphQL, custom) API and allowing you to quickly build an admin interface themed with the elegant Material-UI framework.

In this article, you will use react-admin to build an admin interface that uses the JSONPlaceholder API.

Prerequisites

This tutorial was verified with Node v16.6.1, npm v7.20.3, react v17.0.2, react-admin vv3.17.1, and ra-data-json-server v3.17.1.

Step 1 — Setting Up the Project

To get started, we’re going to create a new React application using create-react-app:

  • npx create-react-app react-admin-example

Next, navigate to the new project directory:

  • cd react-admin-example

Then, install the dependencies for react-admin:

  • npm install react-admin@<3.17.1^> ra-data-json-server@3.17.1<^>

ra-data-json-server is what’s called a data provider. Data providers are what allow react-admin to communicate with your API. Here, we’re using ra-data-json-server because JSONPlaceholder is powered by JSON Server. If you’re using an API that doesn’t exactly match that of JSONPlaceholder, you will need to implement your own data provider. Consult the data provider documentation for more information.

At this point, you have a new React project with react-admin and ra-data-json-server installed.

Step 2 — Building the Application

First, we’ll open up src/App.js in our code editor and add in our root Admin component:

src/App.js
import {
  Admin
} from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');

function App() {
  return (
    <Admin dataProvider={dataProvider} />
  );
}

export default App;

Save the changes to your file and run the application:

  • npm run start

Then, open the application in our browser. It will display a message confirming that react-admin has been properly configured:

Output
Welcome to React-admin Your application is properly configured. Now you can add a <Resource> as child of <Admin>.

Now, we can start mapping the API endpoints into the admin interface.

Step 3 — Using ListGuesser to Map Data

Whenever you add a new endpoint, you first use a guesser. This will take the data from the API and guess what kind of component to output. The first endpoint we’ll add is users, and we’re going to use ListGuesser to automatically render a list of all users:

src/App.js
import {
  Admin,
  Resource,
  ListGuesser,
} from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');

function App() {
  return (
    <Admin dataProvider={dataProvider}>
      <^><Resource
        name="users"
        list={ListGuesser}
      />
    </Admin>
  );
}

export default App;

Save the changes to your file and observe the application in your browser.

There is an admin interface that is automatically populated with a list of users! Including their names, emails, phone number, and more!

It works almost perfectly but guessers aren’t meant to be used permanently. They are only there to help us get started. We’re going to take the guessed list output from the guesser (which can be found in the DevTools console) and use it to create a custom list component:

export const UserList = (props) => (
  <List {...props}>
    <Datagrid rowClick="edit">
      <TextField source="id" />
      <TextField source="name" />
      <TextField source="username" />
      <EmailField source="email" />
      <TextField source="address.street" />
      <TextField source="phone" />
      <TextField source="website" />
      <TextField source="company.name" />
    </Datagrid>
  </List>
);

We’ll take this output and paste it into a new file called Users.js, while making sure to add all the imports from react-admin:

src/Users.js
import {
  List,
  Datagrid,
  TextField,
  EmailField,
} from 'react-admin';

export const UserList = (props) => (
  <List {...props}>
    <Datagrid rowClick="edit">
      <TextField source="id" />
      <TextField source="name" />
      <TextField source="username" />
      <EmailField source="email" />
      <TextField source="address.street" />
      <TextField source="phone" />
      <TextField source="website" />
      <TextField source="company.name" />
    </Datagrid>
  </List>
);

Now we need to replace the ListGuesser with our newly created component:

src/App.js
import {
  Admin,
  Resource,
} from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import {
  UserList,
} from './Users';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');

function App() {
  return (
    <Admin dataProvider={dataProvider}>
      <Resource
        name="users"
        list={UserList}
      />
    </Admin>
  );
}

export default App;

Great! In the browser window, we can verify that the list works exactly as it did with ListGuesser.

Let’s make some changes to UserList to make it a little better. We’ll change the website column to a UrlField to make it clickable. We’ll also add a label to the address and company columns to make it a bit more readable:

src/Users.js
import {
  List,
  Datagrid,
  TextField,
  EmailField,
  UrlField,
} from 'react-admin';

export const UserList = props => (
  <List {...props}>
    <Datagrid rowClick="edit">
      <TextField source="id" />
      <TextField source="name" />
      <TextField source="username" />
      <EmailField source="email" />
      <TextField source="address.street" label="Address" />
      <TextField source="phone" />
      <UrlField source="website" />
      <TextField source="company.name" label="Company" />
    </Datagrid>
  </List>
);

Instead of Address.street the label displays as Address. Instead of Company.name the label displays as Company. Much better!

Step 4 — Using EditGuesser to Map Create, Edit, Delete

Our admin interface works great if you’re just trying to view users, but what if you want to create, edit, or even delete users? Thankfully, react-admin has a way to do this as well. We’re going to use a guesser again, but this time, it’s an EditGuesser:

src/App.js
import {
  Admin,
  Resource,
  EditGuesser,
} from "react-admin";
import jsonServerProvider from 'ra-data-json-server';
import {
  UserList,
} from './Users';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');

function App() {
  return (
    <Admin dataProvider={dataProvider}>
      <Resource
        name="users"
        list={UserList}
        edit={EditGuesser}
      />
    </Admin>
  );
}

export default App;

Now, let’s open up the admin in our browser and click on any user. This will bring up the edit interface, and once again, the guesser does a good job!

We’re going to do the same thing as before and copy the output from the guesser and paste it into our Users.js file. We’re also going to change the id column to a disabled input; you wouldn’t want the id field to be editable!

src/users.js
import {
  List,
  Datagrid,
  TextField,
  EmailField,
  UrlField,
  Edit,
  SimpleForm,
  TextInput,
} from 'react-admin';

export const UserList = props => ( ... );

export const UserEdit = props => (
  <Edit {...props}>
    <SimpleForm>
      <TextInput source="id" disabled />
      <TextInput source="name" />
      <TextInput source="username" />
      <TextInput source="email" />
      <TextInput source="address.street" label="Address" />
      <TextInput source="phone" />
      <TextInput source="website" />
      <TextInput source="company.name" label="Company" />
    </SimpleForm>
  </Edit>
);

And finally, replace the EditGuesser with our custom component:

src/App.js
import {
  Admin,
  Resource,
} from "react-admin";
import jsonServerProvider from 'ra-data-json-server';
import {
  UserList,
  UserEdit,
} from './Users';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');

function App() {
  return (
    <Admin dataProvider={dataProvider}>
      <Resource
        name="users"
        list={UserList}
        edit={UserEdit}
      />
    </Admin>
  );
}

export default App;

Now we have a functional edit interface! Unfortunately, JSONPlaceholder doesn’t allow edits. However, try to edit a user and observe what happens. You will experience the user change for a second before react-admin changes it back to its original form. This is because react-admin uses optimistic rendering. This means that when a user makes a change, react-admin displays that change immediately while sending an update query in the background. This allows for a seamless user experience, with no need to wait for a server response before updating the admin interface.

The only thing we’re missing now is a way to create new users. Since the creation form is so similar to the edit form, we can copy our UserEdit component and call the new component UserCreate. Make sure to remove the id field, since the user can’t have an id before creation.

src/Users.js
import {
  List,
  Datagrid,
  TextField,
  EmailField,
  UrlField,
  Edit,
  SimpleForm,
  TextInput,
  Create,
} from 'react-admin';

export const UserList = props => ( ... );

export const UserEdit = props => ( ... );

export const UserCreate = props => (
  <Create {...props}>
    <SimpleForm>
      <TextInput source="name" />
      <TextInput source="username" />
      <TextInput source="email" />
      <TextInput source="address.street" label="Address" />
      <TextInput source="phone" />
      <TextInput source="website" />
      <TextInput source="company.name" label="Company" />
    </SimpleForm>
  </Create>
);

Now add the new component to App.js:

src/App.js
import {
  Admin,
  Resource,
} from "react-admin";
import jsonServerProvider from 'ra-data-json-server';
import {
  UserList,
  UserEdit,
  UserCreate,
} from './Users';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');

function App() {
  return (
    <Admin dataProvider={dataProvider}>
      <Resource
        name="users"
        list={UserList}
        edit={UserEdit}
        create={UserCreate}
      />
    </Admin>
  );
}

export default App;

And just like that, react-admin will add a Create button to our list of users!

Conclusion

In this article, you used react-admin to build an admin interface that uses the JSONPlaceholder) API.

We’ve created a nice little admin interface using react-admin, but we’ve barely scratched the surface of what it has to offer. react-admin is highly customizable: the functionality and appearance of every component we’ve used so far (and more) can be customized. To learn more, consult the react-admin documentation.

Creative Commons License