はじめに
新規プロジェクトが動き出すたびに、必ずと言っていいほど必要になるのが「管理画面」です。商品データの一覧・編集、ユーザー管理、注文ステータスの変更——業務としての新規性は低いのに、一覧テーブル、フォームバリデーション、検索・フィルタ、権限管理まで、実装すべきものは驚くほど多くあります。毎回スクラッチで作っていては、いくら時間があっても足りません。
React-Adminは、そんな「地味だが手間のかかる」管理画面開発を劇的に効率化してくれるフレームワークです。CRUD(作成・読み取り・更新・削除)画面に必要な機能があらかじめ組み込まれており、APIさえ用意できれば数十分で動く管理画面を立ち上げられます。この記事では、React-Adminの特徴からインストール、実践的な使い方までを解説します。
とはいえ、説明を読むよりも実際に動く管理画面を見た方が早いと思います。<Admin>と<Resource>だけで一覧画面が組み上がる様子をこの場で確認できるので、先に触ってみたい方はこちらからどうぞ。
React-Adminとは
React-Adminは、フランスのmarmelab社が開発するオープンソースのフロントエンドフレームワークです。Material UI・React Hook Form・React Router・TanStack Query(React Query)といった実績あるライブラリの上に構築されており、REST/GraphQLなど45種類以上のAPIに対応する「データプロバイダー」を差し替えるだけで、既存のバックエンドとすぐに接続できます。
主な特徴
- API非依存 - REST、GraphQL、Firebase、Supabaseなど、多様なバックエンドに対応するデータプロバイダーが用意されている
- CRUD機能が標準装備 - 一覧、詳細、作成、編集画面と、検索・ソート・ページネーション・一括操作が最初から使える
- 高いカスタマイズ性 - 各画面はReactコンポーネントの組み合わせで構成されており、部分的な差し替えも容易
- 認証・権限管理を内蔵 -
authProviderによるログイン制御や、ロールに応じた表示切り替えに標準対応 - TypeScriptファースト - 型定義が同梱されており、リソースやフィールドの型安全な記述が可能
インストール
すでにReactプロジェクトがある場合は、react-admin本体とデータプロバイダーをインストールします。
# npm
npm install react-admin ra-data-json-server
# yarn
yarn add react-admin ra-data-json-server
# pnpm
pnpm add react-admin ra-data-json-server
新規にプロジェクトを始める場合は、公式のスターターコマンドを使うと初期設定込みで生成できます。
npm create react-admin@latest my-admin
React-Adminのサンプルを動かす
React-Adminの核心は、<Admin>にdataProviderを渡し、<Resource>でリソース(テーブル)を登録するだけで一覧・検索・ソート機能付きの画面が動き出す点にあります。ここでは外部APIの代わりに、インメモリ用のdataProviderであるra-data-fakerestを使い、ハードコードした書籍データをその場で表示・検索できるサンプルを用意しました。List・Datagrid・TextField・SearchInputといった標準コンポーネントの組み合わせだけで、実用的な一覧画面が組み上がることを確認できます。
要点だけを抜き出すと、次のようになります。
import { Admin, Resource, List, Datagrid, TextField, NumberField } from "react-admin";
import fakeDataProvider from "ra-data-fakerest";
const dataProvider = fakeDataProvider({
books: [
{ id: 1, title: "吾輩は猫である", author: "夏目漱石", year: 1905 },
{ id: 2, title: "銀河鉄道の夜", author: "宮沢賢治", year: 1934 },
],
});
const BookList = () => (
<List>
<Datagrid>
<TextField source="title" />
<TextField source="author" />
<NumberField source="year" />
</Datagrid>
</List>
);
export const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="books" list={BookList} />
</Admin>
);
実際に動かせるものが下です。右上の検索ボックスに文字を入力すると、dataProviderへのqパラメータによる絞り込みがその場で反映されます。
検索ボックスに「猫」と入力すると吾輩は猫であるだけに絞り込まれ、「夏目」と入力すると著者名でも一致することが分かるはずです。これはra-data-fakerestがqパラメータを全フィールドに対する正規表現検索として扱っているためで、実運用時はここが実際のAPIへのクエリに置き換わります。books配列に行を追加したり、NumberFieldをDateFieldに差し替えたりして、一覧の見た目がどう変わるか試してみてください。
基本的な使い方
まずはAdminコンポーネントにResourceを登録するだけの、最小構成から始めましょう。ListGuesserやEditGuesserを使うと、APIのレスポンスからフィールド構成を自動推測してくれるため、画面の中身を1行も書かずに動作確認ができます。
import { Admin, Resource, ListGuesser, EditGuesser } from "react-admin";
import jsonServerProvider from "ra-data-json-server";
const dataProvider = jsonServerProvider("https://jsonplaceholder.typicode.com");
export const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts" list={ListGuesser} edit={EditGuesser} />
<Resource name="users" list={ListGuesser} />
</Admin>
);
動作を確認できたら、実際の画面を自前のコンポーネントに置き換えていきます。以下は投稿一覧と編集フォームを明示的に定義した例です。
import {
List,
Datagrid,
TextField,
DateField,
EditButton,
Edit,
SimpleForm,
TextInput,
required,
} from "react-admin";
export const PostList = () => (
<List>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="title" />
<DateField source="publishedAt" />
<EditButton />
</Datagrid>
</List>
);
export const PostEdit = () => (
<Edit>
<SimpleForm>
<TextInput source="title" validate={required()} />
<TextInput source="body" multiline rows={5} />
</SimpleForm>
</Edit>
);
Resourceにこれらを渡せば、一覧から編集、保存までがそのまま動く管理画面になります。
<Resource name="posts" list={PostList} edit={PostEdit} />
実践的なユースケース
React-Adminでリレーションを持つデータを表示する
管理画面では「投稿とその著者」のように、複数リソースを紐付けて表示したいケースが多くあります。React-AdminではReferenceFieldとReferenceInputを使うことで、外部キーを自然に扱えます。
import { ReferenceField, ReferenceInput, TextField, AutocompleteInput } from "react-admin";
// 一覧画面: 著者名を関連リソースから表示
<ReferenceField source="userId" reference="users">
<TextField source="name" />
</ReferenceField>;
// 編集画面: 著者を検索して選択
<ReferenceInput source="userId" reference="users">
<AutocompleteInput optionText="name" />
</ReferenceInput>;
実際にReferenceFieldが著者名を解決する様子を、書籍データと著者データをどちらもインメモリで用意したサンプルで確認できます。authorsを<Resource>として登録しなくても、ReferenceFieldが裏でdataProvider.getMany()を呼び出して参照先を解決してくれる点がポイントです。
authorId: 2の行に注目すると、ReferenceFieldが自動的に宮沢賢治という名前を解決しているのが分かります。books配列のauthorIdを存在しないID(例: 99)に変えてみると、参照が解決できずセルが空表示になる挙動も確認できます。
React-Adminで権限に応じて画面を出し分ける
authProviderを実装すると、ログイン状態の管理に加えて、ロールごとに操作できる範囲を制限できます。usePermissionsフックで現在のユーザー権限を取得し、UIの出し分けに利用します。
import { usePermissions, DeleteButton, EditButton } from "react-admin";
const PostListActions = () => {
const { permissions } = usePermissions();
return permissions === "admin" ? (
<>
<EditButton />
<DeleteButton />
</>
) : (
<EditButton />
);
};
実際にauthProvider.getPermissions()の戻り値でボタンの表示が切り替わる様子を、ロールをボタンで切り替えられるサンプルで確認できます。ロールを変更するたびに<Admin>をkey付きで作り直し、authProviderを再評価させています。
「クリックで切替」ボタンを押してroleをadminにすると、行ごとに削除ボタンが現れます。editorに戻すとボタンが消え、usePermissionsがauthProviderの戻り値をそのままUIの出し分けに使っていることが確認できます。実際のアプリではgetPermissionsの中でトークンのデコードやAPI呼び出しを行い、ロール文字列を返す形になります。
React-Adminでカスタムダッシュボードを作る
トップページには、件数集計や直近の更新情報など、業務でよく確認する情報をまとめたダッシュボードを表示できます。dataProviderから取得したデータを、通常のReactコンポーネントと同様に描画するだけです。
import { useGetList } from "react-admin";
import { Card, CardContent, Typography } from "@mui/material";
export const Dashboard = () => {
const { total, isPending } = useGetList("posts", {
pagination: { page: 1, perPage: 1 },
});
return (
<Card>
<CardContent>
<Typography variant="h6">投稿数</Typography>
<Typography variant="h3">{isPending ? "…" : total}</Typography>
</CardContent>
</Card>
);
};
実際にuseGetListが件数を取得する様子を、Adminのdashboardプロパティに差し替えたサンプルで確認できます。orders配列をインメモリで用意し、注文ステータスごとの件数を集計しています。
Adminにdashboardプロパティを渡すだけで、ログイン後の初期画面をこの内容に差し替えられます。orders配列にstatus: 'shipped'の行を増やすと「発送済み」の件数がその場で変わるので、useGetListがdataProvider.getList()を呼び直していることが体感できます。左のメニューから「Orders」を開けば、ListGuesserが同じデータからテーブルを自動生成する様子も確認できます。
まとめ
React-Adminは、一覧・検索・編集・削除といった管理画面に不可欠な機能をあらかじめ備えつつ、Material UIベースのコンポーネントを自由に組み替えられる柔軟性を兼ね備えたフレームワークです。データプロバイダーを差し替えるだけで既存のAPIと接続できるため、社内ツールから顧客向けの管理コンソールまで幅広く応用できます。CRUD画面の実装に時間を取られていると感じたら、まずはListGuesserとEditGuesserで小さく試してみることをおすすめします。
