Movatterモバイル変換


[0]ホーム

URL:


Next.js Integration

React-admin runs seamlessly onNext.js, with minimal configuration.

Next.js 13 proposes 2 ways to build a React project:

React-admin supports both ways.

Create a Next.js application

Use thecreate-next-app package to create a new Next.js project callednext-admin.

npx create-next-app@latest

A prompt will asks you some questions, feel free to choose answers according to your needs. This tutorial assumes you’re using asrc folder, so answerYes to the 5th question. As for the App Router, you can choose to use it or not, this tutorial will explain how to use both. (For new applications, Next.js recommends using the App Router).

Install Next.js with command line

This creates a project with the following folder structure:

Pages RouterApp Router
Next Admin folder structure with Pages RouterNext Admin folder structure with App Router

Adding React-Admin Dependencies

Add thereact-admin npm package, as well as a data provider package. In this example, we’ll usera-data-json-server to connect to a test API provided byJSONPlaceholder.

cdnext-adminnpminstallreact-admin ra-data-json-server

Tips: If you prefer yarn, you could create the project withnpx create-next-app@latest --use-yarn and add the dependencies withyarn add react-admin ra-data-json-server.

Creating The Admin App Component

Next, create acomponents directory insidesrc, and an admin App component insrc/components/AdminApp.tsx:

// in src/components/AdminApp.tsx"use client";// remove this line if you choose Pages Routerimport{Admin,Resource,ListGuesser,EditGuesser}from"react-admin";importjsonServerProviderfrom"ra-data-json-server";constdataProvider=jsonServerProvider("https://jsonplaceholder.typicode.com");constAdminApp=()=>(<AdmindataProvider={dataProvider}><Resourcename="users"list={ListGuesser}edit={EditGuesser}recordRepresentation="name"/><Resourcename="posts"list={ListGuesser}edit={EditGuesser}recordRepresentation="title"/><Resourcename="comments"list={ListGuesser}edit={EditGuesser}/></Admin>);exportdefaultAdminApp;

This is a minimal configuration to render CRUD pages for users, posts and comments. React-admin will guess the fields to display in the list and edition pages based on the API response.

Exposing The Admin App Component

React-admin is designed as a Single-Page Application, rendered on the client-side. It comes with various client-side only libraries (react-router, emotion, material-ui, react-query). So when you include theAdminApp component in the Next.js app, you must prevent Next.js from rendering it on the server.

To do that, import the<AdminApp> component in Next.js by usinglazy loading and specify thessr option to false.

The file to modify depends on the router system you chose during setup:

  • App Router:src/app/page.tsx,
  • Pages Router:src/pages/index.tsx.
import{NextPage}from"next";importdynamicfrom"next/dynamic";constAdminApp=dynamic(()=>import("@/components/AdminApp"),{ssr:false});constHome:NextPage=()=><AdminApp/>;exportdefaultHome;

Now, start the server withyarn dev, browse tohttp://localhost:3000/, and you should see the working admin:

Working Page

Starting from there, you canAdd an API as described in the next section, and/or add features to the Next.js app, as explained in theGetting started tutorial

Rendering React-Admin In A Sub Route

In many cases, the admin is only a part of the application. For instance, you may want to render the admin in a subpath, e.g./admin.

This implies the creation of a new page in the Next.js app. Create a new file at the following location:

  • App Router:src/app/admin/page.tsx
  • Pages Router:src/pages/admin/index.tsx

No matter which system you choose, the file should contain the same code:

import{NextPage}from"next";importdynamicfrom"next/dynamic";constAdminApp=dynamic(()=>import("@/components/AdminApp"),{ssr:false});constAdmin:NextPage=()=>{return<AdminApp/>;};exportdefaultAdmin;

Now the admin renders athttp://localhost:3000/admin. You can use the Next.js routing system to add more pages - for instance, a frontend app.

Tip: If you migrated from the Pages Router, you might have to delete the.next directory in your project to ensure NextJS bundles the client dependencies correctly.

Adding an API

Next.js allows to serve an API from the same server. Youcould use this to build a CRUD API by hand. However, we consider that building a CRUD API on top of a relational database is a solved problem and that developers shouldn’t spend time reimplementing it.

For instance, if you store your data in aPostgreSQL database, you can usePostgREST to expose the data as a REST API with zero configuration. Even better, you can use a Software-as-a-Service likeSupabase to do that for you.

In such cases, the Next.js API can serve as a Proxy to authenticate client queries and pass them down to Supabase. Let’s see an example in practice.

First, create a Supabase REST API and its associated PostgreSQL database directly on theSupabase website (it’s free for tests and low usage). Once the setup is finished, use the Supabase manager to add the following tables:

  • users with fields:id,name, andemail
  • posts with fields:id,title, andbody
  • comments with fields:id,name,body, andpostId (a foreign key to theposts.id field)

You can populate these tables via the Supabse UI if you want. Supabase exposes a REST API athttps://YOUR_INSTANCE.supabase.co/rest/v1.

Copy the Supabase API URL and service role key into Next.js’s.env.local file:

# in `.env.local`SUPABASE_URL="https://MY_INSTANCE.supabase.co"SUPABASE_SERVICE_ROLE="MY_SERVICE_ROLE_KEY"

Tip: This example uses theservice role key here and not the anonymous role. This allows mutations without dealing with authorization (You may have to modify the safety policies).You shouldn’t do this in production, but use theSupabase authorization feature instead.

Createa “catch-all” API route in the Next.js app by adding a new file at the following location:

  • App Router:src/app/api/admin/[...slug]/route.ts
  • Pages Router:src/pages/api/admin/[[...slug]].ts

/!\ The file name is important: it must beroute.ts in the App Router and[[...slug]].ts in the Pages Router.

From this point on, the logic for handling is different depending on the router.

App Router

// in src/app/api/admin/[...slug]/route.tsexportconstdynamic='force-dynamic';// defaults to autoexportasyncfunctionGET(request:Request){returnhandler(request);}exportasyncfunctionPOST(request:Request){returnhandler(request);}exportasyncfunctionPUT(request:Request){returnhandler(request);}exportasyncfunctionPATCH(request:Request){returnhandler(request);}exportasyncfunctionDELETE(request:Request){returnhandler(request);}asyncfunctionhandler(request:Request){// get part after /api/admin/ in string urlconstrequestUrl=request.url.split('/api/admin')[1];// build the CRUD request based on the incoming requestconsturl=`${process.env.SUPABASE_URL}/rest/v1${requestUrl}`;constoptions:RequestInit={method:request.method,headers:{prefer:(request.headers.get('prefer')asstring)??'',accept:request.headers.get('accept')??'application/json',['content-type']:request.headers.get('content-type')??'application/json',// supabase authenticationapiKey:process.env.SUPABASE_SERVICE_ROLE??'',Authorization:"Bearer"+process.env.SUPABASE_SERVICE_ROLE??'',},};if(request.body){constbody=awaitrequest.json();options.body=JSON.stringify(body);}// call the CRUD APIconstresponse=awaitfetch(url,options);constcontentRange=response.headers.get('content-range');constheaders=newHeaders();if(contentRange){headers.set('Content-Range',contentRange);}constdata=awaitresponse.text();returnnewResponse(data,{status:200,headers,});}

For more information about routes handler with the App Router, seethe official documentation.

Pages Router

This API route redirects all calls from the react-admin app to the Supabase CRUD API:

// in src/pages/api/admin/[[...slug]].tsimport{NextApiRequest,NextApiResponse}from"next";exportdefaultasyncfunctionhandler(req:NextApiRequest,res:NextApiResponse){// get the incoming request URL, e.g. 'posts?limit=10&offset=0&order=id.asc'constrequestUrl=req.url?.substring("/api/admin/".length);// build the CRUD request based on the incoming requestconsturl=`${process.env.SUPABASE_URL}/rest/v1/${requestUrl}`;constoptions:RequestInit={method:req.method,headers:{prefer:req.headers["prefer"]asstring??"",accept:req.headers["accept"]??"application/json",["content-type"]:req.headers["content-type"]??"application/json",// supabase authenticationapiKey:process.env.SUPABASE_SERVICE_ROLE??'',Authorization:"Bearer"+process.env.SUPABASE_SERVICE_ROLE??'',},};if(req.body){options.body=JSON.stringify(req.body);}// call the CRUD APIconstresponse=awaitfetch(url,options);// send the response back to the clientconstcontentRange=response.headers.get("content-range");if(contentRange){res.setHeader("Content-Range",contentRange);}res.end(awaitresponse.text());}

For more information about routes handler with the Pages Router, seethe official documentation.

Tip: Some of this code is really PostgREST-specific. Theprefer header is required to let PostgREST return one record instead of an array containing one record in response togetOne requests. TheContent-Range header is returned by PostgREST and must be passed down to the client. A proxy for another CRUD API will require different parameters.

Data Provider

Finally, update the react-admin data provider to use the Supabase adapter instead of the JSON Server one. As Supabase provides a PostgREST endpoint, we’ll usera-data-postgrest:

npminstall @raphiniert/ra-data-postgrest# oryarn add @raphiniert/ra-data-postgrest
// in src/components/AdminApp.tsximport*asReactfrom"react";import{Admin,Resource,ListGuesser,EditGuesser,fetchUtils}from'react-admin';importpostgrestRestProvider,{IDataProviderConfig,defaultPrimaryKeys,defaultSchema,}from'@raphiniert/ra-data-postgrest';constconfig:IDataProviderConfig={apiUrl:'/api/admin',httpClient:fetchUtils.fetchJson,defaultListOp:'eq',primaryKeys:defaultPrimaryKeys,schema:defaultSchema,};constdataProvider=postgrestRestProvider(config);constAdminApp=()=>(<AdmindataProvider={dataProvider}><Resourcename="users"list={ListGuesser}edit={EditGuesser}recordRepresentation="name"/><Resourcename="posts"list={ListGuesser}edit={EditGuesser}recordRepresentation="title"/><Resourcename="comments"list={ListGuesser}edit={EditGuesser}/></Admin>);exportdefaultAdminApp;

Your react-admin app now uses the Supabase API to fetch and update data.


[8]ページ先頭

©2009-2025 Movatter.jp