React Adminでデータ駆動型アプリを構築する
管理画面のダッシュボードをゼロから構築した経験があれば—テーブル、フォーム、ページネーション、API呼び出しを手作業で配線し—ビジネスロジックを一行書く前にどれだけのボイラープレートが必要かご存知でしょう。React Adminは、あらゆるAPI上でCRUDアプリを構築するための構造化されたフレームワークを提供することで、この問題を解決します。この記事では、React Adminがバックエンド非依存で真に再利用可能なアーキテクチャをどのように実現しているかに焦点を当てて解説します。
重要なポイント
- React Adminは、データ駆動型の管理ダッシュボードを構築するためのReactフレームワークであり、UIテンプレートではありません。
dataProvider抽象化を通じて、データレイヤーとUIレイヤーを分離します。 dataProviderは、React AdminをあらゆるバックエンドーREST、GraphQL、Supabaseなどーに適応させる9つのコアメソッドを中心に構築されており、フレームワークを真にバックエンド非依存にしています。- リストビューと編集ビューは宣言的です:フィールドコンポーネントと入力コンポーネントを組み合わせれば、React Adminがデータ取得、ページネーション、ソート、リレーションシップの解決を自動的に処理します。
- 認証、ロールベースのアクセス制御、リアルタイム更新は、個別のプロバイダーとオプションの拡張機能を通じて処理され、コアフレームワークは集中的でモジュラーな状態を保ちます。
React Adminの実体
React AdminはUIテンプレートではありません。データ駆動型の管理ダッシュボードと内部ツール用に特別に構築されたReactフレームワークです。レコードのリスト表示、作成、編集、削除のためのコンポーネントが付属していますが、真の価値はデータレイヤーとUIレイヤーを分離する方法にあります。
React Admin v5のコアは、React Query、react-hook-form、react-routerで構築されています。デフォルトではMUIを使用しますが、それに限定されません—React Adminはヘッドレス使用をサポートしており、必要に応じて独自のコンポーネントライブラリを導入できます。
3つの構成要素:Admin、Resource、dataProvider
すべてのReact Adminアプリは3つの概念から始まります:
<Admin>— すべてを結びつけるルートコンポーネント<Resource>— 名前をCRUDビューのセットとAPIエンドポイントにマッピングdataProvider— React Adminとバックエンド間のアダプター
import { Admin, Resource } from "react-admin"
import { dataProvider } from "./dataProvider"
import { MovieList } from "./MovieList"
import { MovieEdit } from "./MovieEdit"
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="movies" list={MovieList} edit={MovieEdit} />
</Admin>
)
ユーザーが映画リストに移動すると、React AdminはdataProvider.getList("movies", params)を呼び出します。レコードを編集すると、dataProvider.update("movies", params)を呼び出します。UIは直接APIと通信することはありません。
React Admin dataProviderの仕組み
dataProviderは9つのコアメソッドを中心に構築されています:getList、getOne、getMany、getManyReference、create、update、updateMany、delete、deleteManyです。各メソッドはリクエストオブジェクトを受け取りPromiseを返し、プロバイダーは必要に応じて追加のメソッドで拡張できます。
const dataProvider = {
getList: async (resource, params) => {
const { page, perPage } = params.pagination
const { field, order } = params.sort
const url = `${apiUrl}/${resource}?page=${page}&perPage=${perPage}&sort=${field}&order=${order}`
const { json, headers } = await httpClient(url, { signal: params.signal })
return {
data: json,
total: parseInt(headers.get("content-range").split("/").pop(), 10),
}
},
// ...その他のメソッド
}
React Adminは、バックエンドがREST、GraphQL、Supabase、さらにはIndexedDBであっても気にしません。すべてのレコードが一貫したidフィールドを持ち、dataProviderが期待される形式を返す限り、動作します。一般的なバックエンド用の事前構築されたアダプター—ra-data-simple-rest、ra-data-graphqlなど—が存在するため、多くの場合ゼロから書く必要はありません。
認証の処理
認証はdataProviderに組み込まれていません。React Adminは、ログイン、ログアウト、権限チェックに別のauthProviderを使用します。一般的なパターンは、ログイン後にトークンを保存し、リクエストを行う際にdataProvider内でそれを読み取ることですが、React Adminは外部のIDプロバイダーとの統合もサポートしています。
const httpClient = (url, options = {}) => {
options.user = {
authenticated: true,
token: localStorage.getItem("token"),
}
return fetchUtils.fetchJson(url, options)
}
Discover how at OpenReplay.com.
リストビューと編集ビューの構築
dataProviderが配線されたら、ビューの構築はほぼ宣言的です。リストビューの場合、React Adminの<Datagrid>コンポーネントは、組み合わせたフィールドコンポーネントに基づいて列をレンダリングします。なお、<Datagrid>は今でも広く使用されていますが、新しいバージョンではより現代的な代替として<DataTable>も導入されています。
import { List, Datagrid, TextField, DateField, ReferenceField } from "react-admin"
export const MovieList = () => (
<List>
<Datagrid rowClick="edit">
<TextField source="title" />
<DateField source="release" />
<ReferenceField source="director_id" reference="directors">
<TextField source="lastname" />
</ReferenceField>
</Datagrid>
</List>
)
<ReferenceField>は、関連レコードを解決するために自動的にdataProvider.getMany("directors", ...)を呼び出します—手動でのフェッチは不要です。
編集フォームは、<Edit>と<SimpleForm>を使用して同じパターンに従います:
import { Edit, SimpleForm, TextInput, DateInput } from "react-admin"
export const MovieEdit = () => (
<Edit>
<SimpleForm>
<TextInput source="title" />
<DateInput source="release" />
</SimpleForm>
</Edit>
)
カスタムロジックが必要な場合
リソース固有の動作—親が削除される前に関連レコードを削除するなど—の場合、React AdminはwithLifecycleCallbacksを提供します:
import { withLifecycleCallbacks } from "react-admin"
export const dataProvider = withLifecycleCallbacks(baseDataProvider, [
{
resource: "movies",
beforeDelete: async (params, dp) => {
const { data: reviews } = await dp.getList("reviews", {
filter: { movie_id: params.id },
pagination: { page: 1, perPage: 1000 },
sort: { field: "id", order: "DESC" },
})
await dp.deleteMany("reviews", { ids: reviews.map((r) => r.id) })
return params
},
},
])
これにより、ビジネスロジックをコンポーネント全体に散在させることなく、データレイヤーの近くに保つことができます。
React Adminが標準で提供しないもの
コミットする前に知っておくべきいくつかの点:
- RBAC(きめ細かいロールベースのアクセス制御)にはエンタープライズモジュールが必要です;基本的な権限チェックは
authProviderを通じて処理されます - リアルタイム更新には、互換性のあるリアルタイムデータプロバイダーと追加のセットアップが必要です
- ファイルアップロードには、
multipart/form-dataを処理するためのカスタムdataProviderロジックが必要です
React Adminは、Next.js(PagesとApp Routerの両方を含む)などのフレームワークとも互換性があり、デフォルトのセットアップ以外の代替ルーティングソリューションもサポートしています。
まとめ
React Adminの強みは、そのdataProvider抽象化にあります。API に対してこれらのコアメソッドを実装すれば、ソート、フィルタリング、ページネーション、リレーションシップ処理を備えた完全に機能するCRUD管理ダッシュボードが得られます—自分で構築する必要はありません。バックエンドに適合する事前構築されたアダプターから始め、そうでない場合はカスタムのものを書き、アプリが成長するにつれて認証とライフサイクルコールバックを重ねていきます。
よくある質問
はい。React Adminは設計上バックエンド非依存です。公式のra-data-graphqlアダプターを使用するか、必要なメソッドをGraphQLクエリとミューテーションにマッピングするカスタムdataProviderを書くことができます。各レコードに一貫したidフィールドが含まれ、プロバイダーが期待されるレスポンス形式を返す限り、React Adminはバックエンドに関係なく同じように動作します。
React Adminは、dataProviderを通じて自動的に関連レコードを取得するReferenceFieldやReferenceInputなどのリファレンスコンポーネントを提供します。例えば、ReferenceFieldはdataProvider.getManyを呼び出して外部キーを表示値に解決します。コンポーネントツリーでリレーションシップを宣言すれば、React Adminがバックグラウンドでデータ取得とキャッシングを処理します。
オープンソース版は、authProviderを通じた基本的な認証とシンプルな権限チェックをサポートしています。フィールドを非表示にしたり、ロールごとにアクションを制限したりするような、きめ細かいロールベースのアクセス制御には、エンタープライズRBACモジュールが必要です。無料版がニーズを満たすかどうかを判断するために、権限要件を早期に評価してください。
はい。React AdminはデフォルトでMUIを使用しますが、ヘッドレス使用をサポートしており、UI レイヤー全体を独自のコンポーネントライブラリに置き換えることができます。MUIテーマをカスタマイズしたり、個々のコンポーネントをオーバーライドしたり、データ取得、フォーム処理、ルーティングにReact Adminフックを使用しながら完全にカスタムなビューを構築したりすることもできます。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.