diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 6138cda5812..940787cddf9 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -24,7 +24,7 @@ React-admin uses React. We'll use [create-react-admin](https://github.com/marmel yarn create react-admin test-admin ``` -Choose **JSON Server** as the data provider, then **None** as the auth provider. Don't add any resource for now and just press **Enter**. Finally, choose either `npm` or `yarn` and press **Enter**. Once everything is installed, enter the following commands: +Choose **JSON Server** as the data provider, then **None** as the auth provider. Don't add any resource for now and just press **Enter**. Finally, choose either `npm` or `yarn` and press **Enter**. Once everything is installed, type the following commands: ```sh cd test-admin @@ -33,15 +33,48 @@ npm run dev yarn dev ``` -You should be up and running with an empty React admin application on port 5173. +You should be up and running with an empty React admin application on port 5173: -**Tip**: Although this tutorial uses a TypeScript template, you can use react-admin with JavaScript if you prefer. Also, you can use [Vite](https://vitejs.dev/), [create-react-app](./CreateReactApp.md), [Next.js](./NextJs.md), [Remix](./Remix.md), or any other React framework to create your admin app. React-admin is framework-agnostic. +[![Empty Admin](./img/tutorial_empty.png)](./img/tutorial_empty.png) + +**Tip**: Although this tutorial uses [Vite](https://vitejs.dev/) with [TypeScript](https://www.typescriptlang.org/), you can use react-admin with JavaScript if you prefer. Also, you can use [Next.js](./NextJs.md), [Remix](./Remix.md), [create-react-app](./CreateReactApp.md), or any other React framework to create your admin app. React-admin is framework-agnostic. + +Let's take a look at the generated code. The main entry point is `index.tsx`, which renders the `App` component in the DOM: + +```tsx +// in src/index.tsx +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { App } from './App'; + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + +); +``` + +The `` component renders an `` component, which is the root component of a react-admin application. + +```tsx +// in src/App.tsx +import { Admin, Resource, ListGuesser, EditGuesser, ShowGuesser } from 'react-admin'; +import { dataProvider } from './dataProvider'; + +export const App = () => ( + + + +); +``` + +This empty component only defines a `dataProvider` prop. But what is a data provider? ## Using an API As Data Source -React-admin runs in the browser, and fetches data from an API. +React-admin apps are single-Page-Apps (SPAs) running in the browser, and fetching data from an API. Since there is no standard for data exchanges between computers, react-admin needs an adapter to talk to your API. This adapter is called a *Data Provider*. -We'll be using [JSONPlaceholder](https://jsonplaceholder.typicode.com/), a fake REST API designed for testing and prototyping, as the data source for the application. Here is what it looks like: +For this tutorial, we'll be using [JSONPlaceholder](https://jsonplaceholder.typicode.com/), a fake REST API designed for testing and prototyping, as the data source for the application. Here is what it looks like: ``` curl https://jsonplaceholder.typicode.com/users/2 @@ -75,15 +108,20 @@ curl https://jsonplaceholder.typicode.com/users/2 JSONPlaceholder provides endpoints for users, posts, and comments. The admin we'll build should allow to Create, Retrieve, Update, and Delete (CRUD) these resources. -## Making Contact With The API Using a Data Provider +The `test-admin` project you just created already contains a data provider pre-configured for JSONPlaceholder. -The application has been initialized with enough code for react-admin to render an empty app and confirm that the setup is done: +```jsx +// in src/dataProvider.ts +import jsonServerProvider from 'ra-data-json-server'; -[![Empty Admin](./img/tutorial_empty.png)](./img/tutorial_empty.png) +export const dataProvider = jsonServerProvider( + import.meta.env.VITE_JSON_SERVER_URL +); +``` -The `` component renders an `` component, which is the root component of a react-admin application. This component expects a `dataProvider` prop - a function capable of fetching data from an API. Since there is no standard for data exchanges between computers, you will probably have to write a custom provider to connect react-admin to your own APIs - but we'll dive into Data Providers later. For now, let's take advantage of the `ra-data-json-server` data provider, which speaks the same REST dialect as JSONPlaceholder. +This uses a third-party package, `ra-data-json-server`, which maps the JSONPlaceholder API dialect with the react-admin CRUD API. There are [dozens of data provider packages](./DataProviderList.md) for various APIs and databases. You can even write your own data provider if you need to. But for now, let's make sure the app can connect to JSONPlaceholder. -Now it's time to add features! +**Tip**: The `import.meta.env.VITE_JSON_SERVER_URL` expression is a [Vite environment variable](https://vitejs.dev/guide/env-and-mode.html). It's set to `https://jsonplaceholder.typicode.com` in the `.env` file at the root of the project. ## Mapping API Endpoints With Resources @@ -93,20 +131,14 @@ The `` component expects one or more `` child components. Each ```diff // in src/App.tsx --import { Admin } from "react-admin"; -+import { Admin, Resource, ListGuesser } from "react-admin"; -import jsonServerProvider from "ra-data-json-server"; - -const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com'); +import { Admin, Resource, ListGuesser, EditGuesser, ShowGuesser } from 'react-admin'; +import { dataProvider } from './dataProvider'; --const App = () => ; -+const App = () => ( -+ +export const App = () => ( + + -+ -+); - -export default App; + +); ``` The line `` informs react-admin to fetch the "users" records from the [https://jsonplaceholder.typicode.com/users](https://jsonplaceholder.typicode.com/users) URL. `` also defines the React components to use for each CRUD operation (`list`, `create`, `edit`, and `show`). @@ -151,14 +183,12 @@ Then, edit the `App.tsx` file to use this new component instead of `ListGuesser` ```diff // in src/App.tsx --import { Admin, Resource, ListGuesser } from "react-admin"; +-import { Admin, Resource, ListGuesser, EditGuesser, ShowGuesser } from 'react-admin'; +import { Admin, Resource } from "react-admin"; -import jsonServerProvider from "ra-data-json-server"; +import { dataProvider } from './dataProvider'; +import { UserList } from "./users"; -const dataProvider = jsonServerProvider("https://jsonplaceholder.typicode.com"); - -const App = () => ( +export const App = () => ( - + @@ -191,10 +221,12 @@ export const UserList = () => ( ); ``` -The root component, ``, reads the query parameters from the URL, crafts an API call based on these parameters, and puts the result in a React context. It also builds a set of callbacks allowing child components to modify the list filters, pagination, and sorting. `` does a lot of things, yet its syntax couldn't be simpler: +The root component, ``, reads the query parameters from the URL, calls the API based on these parameters, and puts the result in a React context. It also builds a set of callbacks allowing child components to modify the list filters, pagination, and sorting. `` does a lot of things, yet its syntax couldn't be simpler: ```jsx + {/* children */} + ``` This is a good illustration of the react-admin target: helping developers build sophisticated apps in a simple way. @@ -430,17 +462,15 @@ React-admin knows how to take advantage of these foreign keys to fetch reference // in src/App.tsx -import { Admin, Resource } from "react-admin"; +import { Admin, Resource, ListGuesser } from "react-admin"; -import jsonServerProvider from "ra-data-json-server"; +import { dataProvider } from './dataProvider'; import { UserList } from "./users"; -const App = () => ( +export const App = () => ( + ); - -export default App; ``` [![Guessed Post List](./img/tutorial_guessed_post_list.png)](./img/tutorial_guessed_post_list.png) @@ -467,10 +497,11 @@ export const PostList = () => ( // in src/App.tsx -import { Admin, Resource, ListGuesser } from "react-admin"; +import { Admin, Resource } from "react-admin"; +import { dataProvider } from './dataProvider'; +import { PostList } from "./posts"; import { UserList } from "./users"; -const App = () => ( +export const App = () => ( - + @@ -532,10 +563,11 @@ An admin interface isn't just about displaying remote data, it should also allow // in src/App.tsx -import { Admin, Resource } from "react-admin"; +import { Admin, Resource, EditGuesser } from "react-admin"; +import { dataProvider } from './dataProvider'; import { PostList } from "./posts"; import { UserList } from "./users"; -const App = () => ( +export const App = () => ( - + @@ -591,14 +623,12 @@ Use that component as the `edit` prop of the "posts" Resource instead of the gue // in src/App.tsx -import { Admin, Resource, EditGuesser } from "react-admin"; +import { Admin, Resource } from "react-admin"; -import jsonServerProvider from "ra-data-json-server"; +import { dataProvider } from './dataProvider'; -import { PostList } from "./posts"; +import { PostList, PostEdit } from "./posts"; import { UserList } from "./users"; -const dataProvider = jsonServerProvider("https://jsonplaceholder.typicode.com"); - -const App = () => ( +export const App = () => ( - + @@ -674,11 +704,12 @@ To use the new `` components in the posts resource, just add it as ` ```diff // in src/App.tsx import { Admin, Resource } from "react-admin"; +import { dataProvider } from './dataProvider'; -import { PostList, PostEdit } from "./posts"; +import { PostList, PostEdit, PostCreate } from "./posts"; import { UserList } from "./users"; -const App = () => ( +export const App = () => ( - + @@ -792,7 +823,7 @@ The sidebar menu shows the same icon for both posts and users. Customizing the m import PostIcon from "@mui/icons-material/Book"; import UserIcon from "@mui/icons-material/Group"; -const App = () => ( +export const App = () => ( @@ -827,7 +858,7 @@ export const Dashboard = () => ( // in src/App.tsx import { Dashboard } from './Dashboard'; -const App = () => ( +export const App = () => ( // ... @@ -890,7 +921,7 @@ To enable this authentication strategy, pass the `authProvider` to the `` import { Dashboard } from './Dashboard'; import { authProvider } from './authProvider'; -const App = () => ( +export const App = () => ( // ... diff --git a/docs/css/prism.css b/docs/css/prism.css index 34c454167b3..82d95b19e46 100644 --- a/docs/css/prism.css +++ b/docs/css/prism.css @@ -6,7 +6,6 @@ pre[class*="language-"] { background: 0 0; text-shadow: 0 1px #fff; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; - font-size: 1em; text-align: left; white-space: pre; word-spacing: normal;