Π Π°Π·ΡΠ°Π±ΠΎΡΠΊΠ° Π»ΠΈΡΠ½ΠΎΠ³ΠΎ ΠΊΠ°Π±ΠΈΠ½Π΅ΡΠ° ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Π½Π° React: Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΡ ΠΈ ΡΡΠ°ΠΉΠ»ΠΈΠ½Π³
Π ΠΏΡΠ΅Π΄ΡΠ΄ΡΡΠ΅ΠΌ ΠΏΠΎΡΡΠ΅ ΠΌΡ Π½Π°ΡΠ°Π»ΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΡ Π»ΠΈΡΠ½ΠΎΠ³ΠΎ ΠΊΠ°Π±ΠΈΠ½Π΅ΡΠ° Π½Π° React ΠΈ ΡΠ·Π½Π°Π»ΠΈ ΠΊΠ°ΠΊ ΡΡΠΎΡ ΠΏΡΠΎΡΠ΅ΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΡΡΠΊΠΎΡΠΈΡΡ ΠΏΡΠΈ ΠΏΠΎΠΌΠΎΡΠΈ ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠ° React Admin. ΠΡΠ»ΠΈ ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π½Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ ΠΌΠΎΠΌΠ΅Π½ΡΡ: ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠ° ΠΈ ΠΏΠ΅ΡΠ²ΠΈΡΠ½Π°Ρ Π½Π°ΡΡΡΠΎΠΉΠΊΠ°, Π²ΡΠ²ΠΎΠ΄ ΠΏΠ΅ΡΠ΅ΡΠ½Ρ Π΄Π°Π½Π½ΡΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΡΡ ΠΏΠΎ API, ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π·Π°ΠΏΠΈΡΠ΅ΠΉ. ΠΡΡΡΡ ΠΏΠΎΠΊΠ° ΠΈ Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ ΡΠΈΠΊΡΠΈΠ²Π½ΠΎΠ³ΠΎ API, Π½ΠΎ ΠΌΡ ΡΠΆΠ΅ ΡΠ°Π·ΠΎΠ±ΡΠ°Π»ΠΈΡΡ ΠΊΠ°ΠΊ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ.
ΠΠΈΡΠ½ΡΠΉ ΠΊΠ°Π±ΠΈΠ½Π΅Ρ Π½Π΅ Π±ΡΠ» Π±Ρ Π»ΠΈΡΠ½ΡΠΌ, Π΅ΡΠ»ΠΈ Π±Ρ Π½Π΅ Π΄Π°Π²Π°Π» Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΎΠ³ΡΠ°Π½ΠΈΡΠΈΡΡ Π΄ΠΎΡΡΡΠΏ ΠΊ Π΄Π°Π½Π½ΡΠΌ ΠΏΠΎ Π»ΠΎΠ³ΠΈΠ½Ρ ΠΈ ΠΏΠ°ΡΠΎΠ»Ρ. Π ΡΡΠΎΠΉ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΈ ΠΊΠ°ΠΊ ΡΠ°Π· ΠΈ Π·Π°ΠΉΠΌΠ΅ΠΌΡΡ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠ΅ΠΉ ΠΏΡΠΎΡΠ΅ΡΡΠ° Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ. Π’Π°ΠΊ ΠΆΠ΅ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΊΠΎΡΠ½Π΅ΠΌΡΡ Π²ΠΎΠΏΡΠΎΡΠ° ΡΡΠΈΠ»ΠΈΠ·Π°ΡΠΈΠΈ Π½Π°ΡΠ΅ΠΉ Π°Π΄ΠΌΠΈΠ½ΠΈΡΡΡΠ°ΡΠΈΠ²Π½ΠΎΠΉ ΠΏΠ°Π½Π΅Π»ΠΈ Π½Π° React.
ΠΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ
react-admin
ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ Π³ΠΈΠ±ΠΊΠΎ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²ΡΠ²Π°ΡΡ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ. JSONPlaceholder Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ, ΠΏΠΎΡΡΠΎΠΌΡ ΠΌΡ ΡΠΎΠ±ΠΈΡΠ°Π΅ΠΌΡΡ ΡΠΎΠ·Π΄Π°ΡΡ ΡΠΈΠΊΡΠΈΠ²Π½ΡΠΉ ΠΏΡΠΎΡΠ΅ΡΡ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ Π»ΡΠ±ΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΈΠΌΠ΅Π½ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΈ ΠΏΠ°ΡΠΎΠ»Ρ ΠΈ ΡΠΎΡ
ΡΠ°Π½ΡΡΡ ΡΡΠΈ Π·Π½Π°ΡΠ΅Π½ΠΈΡ Π² localStorage
. Π ΠΏΠ°ΠΏΠΊΠ΅ src
ΡΠΎΠ·Π΄Π°ΠΉΡΠ΅ ΡΠ°ΠΉΠ» Ρ ΠΈΠΌΠ΅Π½Π΅ΠΌ authProvider.js
:
// in src/authProvider.js export default { // called when the user attempts to log in login: ({ username }) => { localStorage.setItem('username', username); // accept all username/password combinations return Promise.resolve(); }, // called when the user clicks on the logout button logout: () => { localStorage.removeItem('username'); return Promise.resolve(); }, // called when the API returns an error checkError: ({ status }) => { if (status === 401 || status === 403) { localStorage.removeItem('username'); return Promise.reject(); } return Promise.resolve(); }, // called when the user navigates to a new location, to check for authentication checkAuth: () => { return localStorage.getItem('username') ? Promise.resolve() : Promise.reject(); }, // called when the user navigates to a new location, to check for permissions / roles getPermissions: () => Promise.resolve(), };
AuthProvider
Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ 5 ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ², ΠΊΠ°ΠΆΠ΄ΡΠΉ ΠΈΠ· ΠΊΠΎΡΠΎΡΡΡ
Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ Promise
. ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ Π²ΡΠ·ΠΎΠ²Ρ authProvider
ΡΠ²Π»ΡΡΡΡΡ Π°ΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΠΌΠΈ, Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅ c Π»Π΅Π³ΠΊΠΎΡΡΡΡ Π·Π°ΠΏΡΠΎΡΠΈΡΡ ΡΠ΅ΡΠ²Π΅Ρ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ.
Π§ΡΠΎΠ±Ρ Π²ΠΊΠ»ΡΡΠΈΡΡ ΡΡΡ ΡΡΡΠ°ΡΠ΅Π³ΠΈΡ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ, ΠΏΠ΅ΡΠ΅Π΄Π°ΠΉΡΠ΅ ΠΊΠ»ΠΈΠ΅Π½ΡΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ²ΠΎΠΉΡΡΠ²Π° authProvider
Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ΅ <Admin>
:
<Admin dashboard={Dashboard} authProvider={authProvider} dataProvider={dataProvider}> // ... </Admin>
ΠΠΎΡΠ»Π΅ ΠΏΠ΅ΡΠ΅Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, Π²ΡΠ²Π΅Π΄Π΅ΡΡΡ ΡΠΎΡΠΌΠ° Π²Ρ ΠΎΠ΄Π° Π² ΡΠΈΡΡΠ΅ΠΌΡ, ΠΊΠΎΡΠΎΡΠ°Ρ Π½Π° Π΄Π°Π½Π½ΡΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ ΠΏΡΠΈΠ½ΠΈΠΌΠ°Π΅Ρ Π»ΡΠ±ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅:
ΠΠ΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΎ ΡΠΈΠΏΠ°Ρ ΠΏΠΎΠ»Π΅ΠΉ
Π ΠΏΡΠ΅Π΄ΡΠ΄ΡΡΠ΅ΠΉ ΡΡΠ°ΡΡΠ΅ ΠΌΡ ΠΊΠΎΡΠ½ΡΠ»ΠΈΡΡ Π²ΠΎΠΏΡΠΎΡΠ° ΡΠΈΠΏΠΎΠ² ΠΏΠΎΠ»Π΅ΠΉ ΠΊΠΎΠ³Π΄Π° ΡΠΎΠ·Π΄Π°Π²Π°Π»ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ Π΄ΡΠ½Π½ΡΡ , Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅ΠΌΡΡ Π³Π΅ΡΡΠ΅ΡΠΎΠΌ. React-admin Π΄Π°Π΅Ρ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·Π²ΠΎΠ°ΡΡ ΡΠ°Π·Π½ΡΠ΅ ΡΠΈΠΏΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² Field Π΄Π»Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π΄Π°Π½Π½ΡΡ : ΡΠΈΡΠ»ΠΎ, Π΄Π°ΡΠ°, ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅, HTML, ΠΌΠ°ΡΡΠΈΠ², ΡΡΡΠ»ΠΊΠ° ΠΈ Π΄ΡΡΠ³ΠΈΠ΅.
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΏΠΎΠ»Π΅ Ρ Π°Π΄ΡΠ΅ΡΠΎΠΌ Π²Π΅Π±-ΡΠ°ΠΉΡΠ° Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΠΊΠ°ΠΊ URL. ΠΠΌΠ΅ΡΡΠΎ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡ Π΅Π³ΠΎ Π² Π²ΠΈΠ΄Π΅ ΡΠ΅ΠΊΡΡΠ°, ΠΏΠΎΡΠ΅ΠΌΡ Π±Ρ Π½Π΅ ΠΎΡΠΎΠ±ΡΠ°Π·ΠΈΡΡ Π΅Π³ΠΎ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΊΠ»ΠΈΠΊΠ°Π±Π΅Π»ΡΠ½ΠΎΠΉ ΡΡΡΠ»ΠΊΠΈ? ΠΡΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ ΡΠΎ, ΡΡΠΎ Π΄Π΅Π»Π°Π΅Ρ <UrlField>.
Π react-admin ΠΏΠΎΠ»Ρ ΡΠ²Π»ΡΡΡΡΡ ΠΏΡΠΎΡΡΡΠΌΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°ΠΌΠΈ React. ΠΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ, ΠΎΠ½ΠΈ ΠΏΠΎΠ»ΡΡΠ°ΡΡ record
ΠΈΠ· API (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, { "id": 2, "name": "Ervin Howell", "website": "anastasia.net", ... }
), ΠΈ source
ΠΏΠΎΠ»Π΅ ΠΊΠΎΡΠΎΡΠΎΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ ΠΎΡΠΎΠ±ΡΠ°Π·ΠΈΡΡ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, website
). ΠΡΠΎ ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ, ΡΡΠΎ ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°ΠΏΠΈΡΠ°ΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΏΡΠΎΡΡΠΎ. ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, Π²ΠΎΡ ΡΠΏΡΠΎΡΠ΅Π½Π½Π°Ρ Π²Π΅ΡΡΠΈΡ UrlField
:
// in src/MyUrlField.js import React from 'react'; const MyUrlField = ({ record = {}, source }) => <a href={record[source]}> {record[source]} </a>; export default MyUrlField;
ΠΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΡΠΎΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ Π² <UserList>
Π²ΠΌΠ΅ΡΡΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° <UrlField>
ΠΈ ΠΎΠ½ Π±ΡΠ΄Π΅Ρ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½ΠΎ.
// in src/users.js import React from 'react'; import { List, Datagrid, TextField, EmailField } from 'react-admin'; import MyUrlField from './MyUrlField'; export const UserList = props => ( <List {...props}> <Datagrid rowClick="edit"> ... <MyUrlField source="website" /> ... </Datagrid> </List> );
ΠΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π·Π°ΠΌΠ΅Π½ΠΈΡΡ Π»ΡΠ±ΠΎΠΉ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² react-admin ΡΠ²ΠΎΠΈΠΌ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΠΌ, Π΅ΡΠ»ΠΈ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ Π½Π΅ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ Π²Π°ΡΠΈΠΌ ΠΏΠΎΡΡΠ΅Π±Π½ΠΎΡΡΡΠΌ.
ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΡΡΠΈΠ»Π΅ΠΉ
ΠΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ MyUrlField
– ΠΏΡΠ΅ΠΊΡΠ°ΡΠ½Π°Ρ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΏΡΠΎΠΈΠ»Π»ΡΡΡΡΠΈΡΠΎΠ²Π°ΡΡ, ΠΊΠ°ΠΊ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°ΡΡ ΡΡΠΈΠ»ΠΈ. React-admin ΠΎΠΏΠΈΡΠ°Π΅ΡΡΡ Π½Π° material-ui, Π½Π°Π±ΠΎΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² React, ΡΠΎΠ·Π΄Π°Π½Π½ΡΠΉ ΠΏΠΎ ΠΎΠ±ΡΠ°Π·ΡΡ Π ΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²Π° Google ΠΏΠΎ UI-ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅. Material-ui ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ JSS, ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ CSS-in-JS, Π΄Π»Ρ ΡΡΠΈΠ»ΠΈΠ·Π°ΡΠΈΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ². ΠΠ°Π²Π°ΠΉΡΠ΅ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡΠΌΠΈ JSS, ΡΡΠΎΠ±Ρ ΡΠ΄Π°Π»ΠΈΡΡ ΠΏΠΎΠ΄ΡΠ΅ΡΠΊΠΈΠ²Π°Π½ΠΈΠ΅ ΠΈΠ· ΡΡΡΠ»ΠΊΠΈ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π·Π½Π°ΡΠΎΠΊ:
// in src/MyUrlField.js import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import LaunchIcon from '@material-ui/icons/Launch'; const useStyles = makeStyles({ link: { textDecoration: 'none' }, icon: { width: '0.5em', paddingLeft: 2 } }); const MyUrlField = ({ record = {}, source }) => { const classes = useStyles(); return ( <a href={record[source]} className={classes.link}> {record[source]} <LaunchIcon className={classes.icon} /> </a> ); }; export default MyUrlField;

Π JSS ΡΡΠΈΠ»ΠΈ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΡΡΡΡ ΠΊΠ°ΠΊ ΠΎΠ±ΡΠ΅ΠΊΡΡ JavaScript, ΠΈΠΌΠ΅Π½ΡΡ ΡΠ²ΠΎΠΉΡΡΠ²Π° CSS Π² ΡΡΠΈΠ»Π΅ JS (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, textDecoration
Π²ΠΌΠ΅ΡΡΠΎ text-decoration
). Π§ΡΠΎΠ±Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ ΡΡΠΈ ΡΡΠΈΠ»ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ makeStyles
Π΄Π»Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ React-Ρ
ΡΠΊΠ°. Π₯ΡΠΊ ΡΠΎΠ·Π΄Π°ΡΡ Π½ΠΎΠ²ΡΠ΅ ΠΈΠΌΠ΅Π½Π° ΠΊΠ»Π°ΡΡΠΎΠ² Π΄Π»Ρ ΡΡΠΈΡ
ΡΡΠΈΠ»Π΅ΠΉ ΠΈ Π²Π΅ΡΠ½Π΅Ρ Π½ΠΎΠ²ΡΠ΅ ΠΈΠΌΠ΅Π½Π° ΠΊΠ»Π°ΡΡΠΎΠ² Π² ΠΎΠ±ΡΠ΅ΠΊΡΠ΅ ΠΊΠ»Π°ΡΡΠΎΠ². ΠΠ°ΡΠ΅ΠΌ Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΡΠΈ ΠΈΠΌΠ΅Π½Π° className
prop, ΠΊΠ°ΠΊ Π΅ΡΠ»ΠΈ Π±Ρ Π²Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΠΈ ΠΎΠ±ΡΡΠ½ΡΠΉ ΠΊΠ»Π°ΡΡ CSS.
Π JSS Π΅ΡΡΡ Π³ΠΎΡΠ°Π·Π΄ΠΎ Π±ΠΎΠ»ΡΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠ΅ΠΉ, ΠΎ ΠΊΠΎΡΠΎΡΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠΎΡΠΈΡΠ°ΡΡ Π² Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ ΠΏΠΎ Material-UI. Π’Π°ΠΊ ΠΆΠ΅ Material-UI ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ Π΄ΡΡΠ³ΠΈΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΡ CSS-in-JS, Π²ΠΊΠ»ΡΡΠ°Ρ Styled Components.
ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π²Π·Π°ΠΈΠΌΠΎΡΠ²ΡΠ·Π΅ΠΉ
Π Π½Π°ΡΠ΅ΠΌ ΡΠΈΠΊΡΠΈΠ²Π½ΠΎΠΌ API ΠΎΡ JSONPlaceholder ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΡΡ Π·Π°ΠΏΠΈΡΠΈ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΉ post
ΠΊΠΎΡΠΎΡΡΠ΅ ΡΠΎΠ΄Π΅ΡΠΆΠ°Ρ ΠΏΠΎΠ»Π΅ userId
ΡΠΊΠ°Π·ΡΠ²Π°ΡΡΠ΅Π΅ Π½Π° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ. ΠΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΏΡΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°Π±ΠΎΡΡ ΡΠΎ Π²Π·Π°ΠΈΠΌΠΎΡΠ²ΡΠ·ΡΠΌΠΈ Π² Π΄Π°Π½Π½ΡΡ
.
React-admin Π·Π½Π°Π΅Ρ, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΡΠΈ Π²Π½Π΅ΡΠ½ΠΈΠ΅ ΠΊΠ»ΡΡΠΈ Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΡΡΡΠ»ΠΎΠΊ. ΠΠ°Π²Π°ΠΉΡΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠΈΠΌ, ΠΊΠ°ΠΊ ListGuesser
ΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ ΠΈΠΌΠΈ, ΡΠΎΠ·Π΄Π°Π² Π½ΠΎΠ²ΡΠΉ <Resource>
Π΄Π»Ρ ΠΊΠΎΠ½Π΅ΡΠ½ΠΎΠΉ ΡΠΎΡΠΊΠΈ API /posts
:
... import { Admin, Resource, ListGuesser } from 'react-admin'; ... const App = () => ( <Admin dataProvider={dataProvider} authProvider={authProvider}> <Resource name='posts' list={ListGuesser} /> ... </Admin> ); ...

ListGuesser
ΠΏΡΠ΅Π΄Π»Π°Π³Π°Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΄Π»Ρ ΠΏΠΎΠ»Ρ userId
. ΠΠ°Π²Π°ΠΉΡΠ΅ ΠΏΠΎΠΈΠ³ΡΠ°Π΅ΠΌ Ρ ΡΡΠΈΠΌ Π½ΠΎΠ²ΡΠΌ ΠΏΠΎΠ»Π΅ΠΌ, ΡΠΎΠ·Π΄Π°Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ PostList
Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ ΠΊΠΎΠ΄Π°, ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ Π³ΡΡΡΠ΅ΡΠΎΠΌ:
// in src/posts.js import React from 'react'; import { List, Datagrid, TextField, ReferenceField } from 'react-admin'; export const PostList = props => ( <List {...props}> <Datagrid rowClick='edit'> <ReferenceField source='userId' reference='users'> <TextField source='id' /> </ReferenceField> <TextField source='id' /> <TextField source='title' /> <TextField source='body' /> </Datagrid> </List> );
// in src/App.js ... import { Admin, Resource } from 'react-admin'; import { PostList } from './posts'; ... <Resource name="posts" list={PostList} /> ...
ΠΡΠΈ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΈ ΡΠΏΠΈΡΠΊΠ° ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅Ρ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ Π°Π²ΡΠΎΡΠ° ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π² Π²ΠΈΠ΄Π΅ <TextField>. ΠΡΠΎ ΠΏΠΎΠ»Π΅ id Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ Π±ΠΎΠ»ΡΡΠΎΠ³ΠΎ Π·Π½Π°ΡΠ΅Π½ΠΈΡ, Π²ΠΌΠ΅ΡΡΠΎ ΡΡΠΎΠ³ΠΎ Π΄Π°Π²Π°ΠΉΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΠΈΠΌΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ Π² src/posts.js
Π²ΠΌΠ΅ΡΡΠΎ <TextField source="id" />
ΠΏΠΎΡΡΠ°Π²ΠΈΠΌ <TextField source="name" />
.
// in src/posts.js ... <ReferenceField source='userId' reference='users'> <TextField source='name' /> </ReferenceField> ...
Π‘ΠΏΠΈΡΠΎΠΊ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ ΡΠ΅ΠΏΠ΅ΡΡ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅Ρ ΠΈΠΌΠ΅Π½Π° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΡΡΠΎΠΊΠ΅.

ΠΠ»Ρ ΡΠΏΡΠ°Π²ΠΊΠΈ: ΡΠ°ΠΌΠΎΡΡΠΎΡΡΠ΅Π»ΡΠ½ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ <ReferenceField>
Π½ΠΈΡΠ΅Π³ΠΎ Π½Π΅ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅Ρ. ΠΠ½ ΠΏΡΠΎΡΡΠΎ Π²ΡΠ±ΠΈΡΠ°Π΅Ρ ΡΠ²ΡΠ·Π°Π½Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ ΠΈ ΠΏΠ΅ΡΠ΅Π΄Π°Π΅Ρ ΠΈΡ
Π² Π²ΠΈΠ΄Π΅ record
ΡΠ²ΠΎΠ΅ΠΌΡ Π΄ΠΎΡΠ΅ΡΠ½Π΅ΠΌΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ (Π² Π½Π°ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°Π΅ ΡΡΠΎ <TextField>
). ΠΠ°ΠΊ ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ <List>
, Π²ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ <Reference>
ΠΎΡΠ²Π΅ΡΠ°ΡΡ ΡΠΎΠ»ΡΠΊΠΎ Π·Π° Π²ΡΠ±ΠΎΡΠΊΡ ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΡ Π΄Π°Π½Π½ΡΡ
ΠΈ Π΄Π΅Π»Π΅Π³ΠΈΡΡΡΡ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³ ΡΠ²ΠΎΠΈΠΌ Π΄ΠΎΡΠ΅ΡΠ½ΠΈΠΌ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΠΌ.
ΠΠ±ΡΠ°ΡΠΈΡΠ΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅: Π΅ΡΠ»ΠΈ Π²Ρ ΠΏΠΎΡΠΌΠΎΡΡΠΈΡΠ΅ Π½Π° Π²ΠΊΠ»Π°Π΄ΠΊΡ network Π²Π°ΡΠ΅Π³ΠΎ Π±ΡΠ°ΡΠ·Π΅ΡΠ°, ΡΠΎ Π·Π°ΠΌΠ΅ΡΠΈΡΠ΅, ΡΡΠΎ react-admin ΠΎΠ±ΡΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ Π·Π°ΠΏΡΠΎΡΡ ΠΊ /user ΠΈ Π²ΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ΄ΠΈΠ½ HTTP-Π·Π°ΠΏΡΠΎΡ Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ Π²ΡΠ΅ΠΉ ΡΠ°Π±Π»ΠΈΡΡ Π΄Π°Π½Π½ΡΡ . ΠΡΠ° ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ Π΄Π΅Π»Π°Π΅Ρ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ Π±ΠΎΠ»Π΅Π΅ Π±ΡΡΡΡΡΠΌ ΠΈ ΠΎΡΠ·ΡΠ²ΡΠΈΠ²ΡΠΌ.
Π§ΡΠΎΠ±Ρ Π·Π°Π²Π΅ΡΡΠΈΡΡ ΡΠΏΠΈΡΠΎΠΊ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΉ, ΠΏΠΎΠΌΠ΅ΡΡΠΈΡΠ΅ ΠΏΠΎΠ»Π΅ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠ° Π·Π°ΠΏΠΈΡΠΈ id
Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ ΡΡΠΎΠ»Π±ΡΠ° ΠΈ ΡΠ΄Π°Π»ΠΈΡΠ΅ ΠΏΠΎΠ»Π΅ body
. Π‘ ΡΠΎΡΠΊΠΈ Π·ΡΠ΅Π½ΠΈΡ UX ΠΏΠΎΠ»Ρ, Π±ΠΎΠ»ΡΡΠΈΠΌ ΡΠ°ΡΡΡΠΌ ΡΠ΅ΠΊΡΡΠ° Π½Π΅ ΡΡΠΎΠΈΡ ΠΏΠΎΡΠ²Π»ΡΡΡΡΡ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ Π΄Π°Π½Π½ΡΡ
, Π° ΡΠΎΠ»ΡΠΊΠΎ Π² ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΡΡ
ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡΡ
. ΠΡΠΎΠΌΠ΅ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ Π²ΡΠ΄Π΅Π»ΠΈΡΡ Π΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ Β«ΠΡΠ°Π²ΠΊΠ°Β» (Edit), Π΄Π°Π²Π°ΠΉΡΠ΅ Π·Π°ΠΌΠ΅Π½ΠΈΠΌ rowClick
ΠΊΠ½ΠΎΠΏΠΊΠΎΠΉ ΡΠ²Π½ΠΎΠ³ΠΎ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ:
// in src/posts.js import React from 'react'; import { List, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin'; export const PostList = props => ( <List {...props}> <Datagrid> <TextField source='id' /> <ReferenceField source='userId' reference='users'> <TextField source='name' /> </ReferenceField> <TextField source='title' /> <EditButton /> </Datagrid> </List> );

ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠ΅ΠΉ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΈ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΡ
ΠΠΎΠ΄ΡΠΎΠ±Π½ΠΎ ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π½Π½ΠΎΠΌΡ ΡΠ°Π½Π΅Π΅ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ, ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°ΡΡ ΠΈ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΠΈ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΉ. ΠΠ»Ρ ΡΡΠΎ ΠΏΡΠΈΠΌΠ΅Π½ΠΈΠΌ Π·Π½Π°ΠΊΠΎΠΌΡΠΉ <EditGuesser>
, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΡΡΡΡΠΊΡΡΡΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°, Π° Π·Π°ΡΠ΅ΠΌ Π½Π° Π΅Ρ ΠΎΡΠ½ΠΎΠ²Π΅ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ ΠΈ, ΠΏΡΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ, Π²Π½Π΅ΡΠ΅ΠΌ Π² Π½Π΅Π³ΠΎ ΠΊΠΎΡΡΠ΅ΠΊΡΠΈΠ²Ρ.
export const PostEdit = props => ( <Edit {...props}> <SimpleForm> <TextInput disabled source='id' /> <ReferenceInput source='userId' reference='users'> <SelectInput optionText='name' /> </ReferenceInput> <TextInput source='title' /> <TextInput multiline source='body' /> </SimpleForm> </Edit> );
ΠΠ»Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΡΠ½ΠΊΡΠΈΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ PostCreate:
export const PostCreate = props => ( <Create {...props}> <SimpleForm> <ReferenceInput source='userId' reference='users'> <SelectInput optionText='name' /> </ReferenceInput> <TextInput source='title' /> <TextInput multiline source='body' /> </SimpleForm> </Create> );
Π Π΅Π³ΠΈΡΡΡΠΈΡΡΠ΅ΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ Π² App.js ΠΈ ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΠ°Π±ΠΎΡΠΈΠΉ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π» ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ.
import React from 'react'; import { Admin, Resource } from 'react-admin'; import authProvider from './authProvider'; import { PostList, PostEdit, PostCreate } from './posts'; import { UserList, UserEdit, UserCreate } from './users'; import jsonServerProvider from 'ra-data-json-server'; const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com'); const App = () => ( <Admin dataProvider={dataProvider} authProvider={authProvider}> <Resource name='posts' list={PostList} edit={PostEdit} create={PostCreate} /> <Resource name='users' list={UserList} edit={UserEdit} create={UserCreate} /> </Admin> ); export default App;
Π‘ΡΡΠ°Π½ΠΈΡΠ° ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈΠΌΠ΅Π΅Ρ Π½Π΅Π±ΠΎΠ»ΡΡΡΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ: ΠΎΠ½Π° ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠ³ΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° (ΡΠ΅ΠΊΡΡ, ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅ΠΌΡΠΉ Π² Π²Π΅ΡΡ Π½Π΅ΠΉ ΠΏΠ°Π½Π΅Π»ΠΈ). ΠΠ°Π²Π°ΠΉΡΠ΅ Π½Π°ΡΡΡΠΎΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° title:
// in src/posts.js ... const PostTitle = ({ record }) => { return <span>Post {record ? `"${record.title}"` : ''}</span>; }; export const PostEdit = props => ( <Edit title={<PostTitle />} {...props}> ... </Edit> );

ΠΠ° ΡΡΠΎΠΌ ΡΡΠ°ΠΏΠ΅ ΠΌΡ ΡΠΆΠ΅ ΠΈΠΌΠ΅Π΅ΠΌ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΏΡΡΡΡ Ρ ΠΎΡΡ ΠΏΠΎΠΊΠ° ΠΈ Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ΠΌ ΠΊ ΡΠΈΠΊΡΠΈΠ²Π½ΠΎΠΌΡ API. Π ΡΠ»Π΅Π΄ΡΡΡΠ΅ΠΉ ΡΠ°ΡΡΠΈ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΈ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠΈΡΠΊΠ° ΠΈ ΡΠΈΠ»ΡΡΡΠΎΠ², ΠΊΠ°ΡΡΠΎΠΌΠΈΠ·Π°ΡΠΈΡ ΠΌΠ΅Π½Ρ ΠΈ Π΄ΠΎΠΌΠ°ΡΠ½Π΅ΠΉ ΡΡΡΠ°Π½ΠΈΡΡ, Π° ΡΠ°ΠΊ ΠΆΠ΅ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΈ Π½Π° ΠΌΠΎΠ±ΠΈΠ»ΡΠ½ΡΡ ΡΡΡΡΠΎΠΉΡΡΠ²Π°Ρ .