diff --git a/docs/Architecture.md b/docs/Architecture.md index 8f54e23b621..16c5a00f80e 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -1,75 +1,199 @@ --- layout: default -title: "Architecture" +title: "Key Concepts" --- -# Architecture +# Key Concepts -React-admin relies on a few design decisions that structure its codebase. +React-admin relies on a several design decisions that structure its codebase. -## Model View Controller +## Single-Page Application -React-admin loosely implements [the Model-View-Controller pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) for page components, and for complex components. +React-admin is specifically designed to build [Single-Page Applications (SPA)](https://en.wikipedia.org/wiki/Single-page_application). In a react-admin app, the browser fetches the required HTML, CSS, and JavaScript to render the application only once. Subsequently, data is fetched from APIs through AJAX calls. This is in contrast to traditional web applications, where the browser fetches a new HTML page for each screen. -- The Controller logic is provided by React hooks (e.g. `useListController`). -- The view logic by React components (e.g. ``). -- The model logic is up to the developer, and react-admin only forces the interface that the model must expose via its Providers. +![SPA lifecycle](./img/SPA-lifecycle.png) + +The SPA architecture ensures that react-admin apps are [exceptionally fast](./Features.md#fast), easy to host, and compatible with existing APIs without requiring a dedicated backend. + +To achieve this, react-admin utilizes an internal router, powered by `react-router`, to display the appropriate screen when the user clicks on a link. Developers can define routes using the [``](./Resource.md) component for CRUD routes and the [``](./CustomRoutes.md) component for other routes. + +For example, the following react-admin application: + +```jsx +import { Admin, Resource, CustomRoutes } from 'react-admin'; +import { Route } from 'react-router-dom'; + +export const App = () => ( + + + + + } /> + } /> + + + } /> + } /> + + +); +``` + +Declares the following routes: + +- `/labels`: `` +- `/labels/:id`: `` +- `/labels/:id/show`: `` +- `/genres`: `` +- `/artists`: `` +- `/artists/:id`: `` +- `/artists/create`: `` +- `/artists/:id/songs`: `` +- `/artists/:id/songs/:songId`: `` +- `/profile`: `` +- `/organization`: `` + +The `` component allows react-admin to automatically link CRUD pages between them, including those for related entities. This approach allows you to think about your application in terms of entities, rather than getting bogged down by managing routes. ## Providers -React-admin apps must integrate with existing backends, but there isn't any standard way to do so (or rather, there are too many standards to do so, e.g. REST, GraphQL, SOAP for data access). +React-admin does not make any assumptions about the specific structure of your API. Instead, it defines its own syntax for data fetching, authentication, internationalization, and preferences. To interact with your API, react-admin relies on adapters called **providers**. + +Providers + +For example, to fetch a list of records from the API, you would use the `dataProvider` object as follows: + +```jsx +dataProvider.getList('posts', { + pagination: { page: 1, perPage: 5 }, + sort: { field: 'title', order: 'ASC' }, + filter: { author_id: 12 }, +}).then(response => { + console.log(response); +}); +// { +// data: [ +// { id: 452, title: "Harry Potter Cast: Where Now?", author_id: 12 }, +// { id: 384, title: "Hermione: A Feminist Icon", author_id: 12 }, +// { id: 496, title: "Marauder's Map Mysteries", author_id: 12 }, +// { id: 123, title: "Real-World Roots of Wizard Spells", author_id: 12 }, +// { id: 189, title: "Your True Hogwarts House Quiz", author_id: 12 }, +// ], +// total: 27 +// } +``` + +The `dataProvider.getList()` method is responsible for translating this request into the appropriate HTTP request to your API. When using the REST data provider, the above code will translate to: + +``` +GET http://path.to.my.api/posts?sort=["title","ASC"]&range=[0, 4]&filter={"author_id":12} + +HTTP/1.1 200 OK +Content-Type: application/json +Content-Range: posts 0-4/27 +[ + { id: 452, title: "Harry Potter Cast: Where Now?", author_id: 12 }, + { id: 384, title: "Hermione: A Feminist Icon", author_id: 12 }, + { id: 496, title: "Marauder's Map Mysteries", author_id: 12 }, + { id: 123, title: "Real-World Roots of Wizard Spells", author_id: 12 }, + { id: 189, title: "Your True Hogwarts House Quiz", author_id: 12 }, +] +``` + +React-admin comes with [more than 50 data providers](./DataProviderList.md) for various backends, including REST, GraphQL, Firebase, Django REST Framework, API Platform, and more. If these providers do not suit your API, you have the flexibility to [develop a custom provider](./DataProviderWriting.md). + +This approach is why react-admin components do not call `fetch` or `axios` directly. Instead, they rely on the data provider to fetch data from the API. Similarly, it is recommended that your custom components follow the same pattern and utilize [data provider hooks](./Actions.md), such as [`useGetList`](./useGetList.md): + +```jsx +import { useGetList } from 'react-admin'; + +const MyComponent = () => { + const { data, total, loading, error } = useGetList('posts', { + pagination: { page: 1, perPage: 5 }, + sort: { field: 'title', order: 'ASC' }, + filter: { author_id: 12 }, + }); + + if (loading) return ; + if (error) return ; + return ( +
+

Found {total} posts matching your query

+
    + {data.map(record => ( +
  • {record.title}
  • + ))} +
+
+ ) +}; +``` + +By using `useGetList`, you gain various benefits beyond a simple `fetch`: it handles user credentials, triggers loading indicators, manages loading states, handles errors, caches results for future use, and controls the data shape, among other things. + +Whenever you need to communicate with a server, you will use these providers. Since they are specialized for their respective domains and tightly integrated with react-admin, they will save you a significant amount of time and effort. + +## Smart Components -So react-admin uses the Adapter pattern to let developers plug their backends in. The idea is that react-admin defines an interface to interact with data, authentication, internationalization, and preferences storage. Developers must provide objects that satisfy these interfaces. How that translates to actual calls to an API is up to the developers. +React-admin was built to avoid rewriting the same code and over again, because most web applications use the same basic building blocks. It provides a library of React components ([more than 150 components to date](./Reference.md#components)). Most of these are **smart components** as they not only handle rendering HTML but also take care of data fetching, state management, and interaction within the application. -For instance, the interface for reading, editing and deleting data is the `dataProvider` interface: +Smart components + +It's important to note that react-admin is not merely a UI Kit like Material UI or Bootstrap. It goes beyond presentation to offer building blocks specifically tailored for data-driven applications. While it is built on top of Material UI, you don't need to be familiar with Material UI to use react-admin effectively. + +For example, to create a custom menu for your application, you can utilize the `` component: ```jsx -const dataProvider = { - getList: (resource, params) => Promise, - getOne: (resource, params) => Promise, - getMany: (resource, params) => Promise, - getManyReference: (resource, params) => Promise, - create: (resource, params) => Promise, - update: (resource, params) => Promise, - updateMany: (resource, params) => Promise, - delete: (resource, params) => Promise, - deleteMany: (resource, params) => Promise, -} +// in src/MyMenu.js +import { Menu } from 'react-admin'; +import LabelIcon from '@mui/icons-material/Label'; + +export const MyMenu = () => ( + + + + + + }/> + +); ``` -Other providers are `authProvider`, for managing authorization and permissions, `i18nProvider`, for managing translations and localization, and `store`, for storing user choices. +In this example, `` links to the `/dashboard` route, `` links to the `list` page defined in the resource configuration from the `` component, and `` is a generic component that you can use to link to any route in your application. The `` component automatically responds to changes on the application location and highlights the current route. Additionally, if you use [Role-Based Access Control](./AuthRBAC.md), users will only see the menu items they have access to. + +Before creating your custom component, it's a good practice to check if react-admin already provides a suitable component with a generic name for your purpose. In many cases, react-admin can save you hours, if not days, of development effort. -## Component Composition +Some of the other useful react-admin components include those for guided tours, sub-forms, login screens, action buttons, calendars, and much more. Each react-admin component can be customized using props, children, and [theme](./Theming.md) to fit your application's specific needs. -React-admin tries to avoid as much as possible having components accepting a huge number of props (we call these "God Components"). Instead, react-admin encourages composition: complex components accept subcomponents (either via children or via specific props) that handle a large share of the logic. +## Composition -For instance, you cannot pass a list of actions to the `` view, but you can pass an `actions` component: +React-admin follows the principle of avoiding components that accept an overwhelming number of props, which are often referred to as "God Components." Instead, react-admin encourages the use of composition, where components accept subcomponents (either through children or specific props) to handle a share of the logic. + +For example, while you cannot directly pass a list of actions to the `` component, you can achieve the same result by passing an `actions` component: ```jsx -import * as React from "react"; import { Button } from '@mui/material'; import { TopToolbar, ShowButton } from 'react-admin'; +export const PostEdit = () => ( + }> + ... + +); + const PostEditActions = () => ( - {/* Add your custom actions */} ); - -export const PostEdit = () => ( - }> - ... - -); ``` -This allows overriding parts of the logic of a component by composing it with another component. +This approach enables you to override specific parts of the logic of a component by composing it with another component. -Many react-admin components can be overridden by passing custom components as children or via props. +Many react-admin components can be easily customized by passing custom components as children or through props. -The drawback is that react-admin sometimes forces you to override several components just to enable one feature. For instance, to override the Menu, you must pass a custom Menu component to a custom ``, and pass the custom `` to ``: +The trade-off with this approach is that sometimes react-admin may require you to override several components just to enable one specific feature. For instance, to override the Menu, you must pass a custom Menu component to a custom ``, and pass that custom `` to the `` component: ```jsx // in src/Layout.js @@ -88,96 +212,231 @@ const App = () => ( ); ``` -We consider that this drawback is acceptable, especially considering the benefits offered by composition. - -## User Experience Is King - -React-admin has two sets of users: - -- End users, who use the react-admin app in their browser -- Developers, who build the react-admin app in their IDE - -For each feature, we design the User Experience (UX) and the Developer Experience (DX) carefully. +Although this drawback exists, we accept it because the use of composition in react-admin makes the components highly extensible, and it significantly improves the readability and maintainability of the code. -For the visual part, react-admin builds upon Material UI, which is the implementation of the Material Design System. It's a great help to build usable, consistent user interfaces, but it's not enough. +## Hooks -We spend a great deal of time refining the UI to make it as intuitive as possible. We pay attention to small alignment glitches, screen flashes, and color inconsistencies. We iterate with every customer feedback, to remove visual and animation problems that occur in real-life applications. +When you find that you cannot tweak a react-admin component using props, you can always turn to the lower-level API: hooks. In fact, react-admin is built on top of a headless library called `ra-core`, which primarily consists of hooks. These hooks hide the framework's implementation details, allowing you to focus on your business logic. It's perfectly normal to use react-admin hooks in your own components if the default UI doesn't meet your specific requirements. -React-admin produces a user interface that is voluntarily bland by default because we want to emphasize content rather than chrome. - - +For example, the `` button renders a confirmation dialog when clicked and then calls the `dataProvider.delete()` method for the current record. If you want the same feature but with a different UI, you can use the `useDeleteWithConfirmController` hook: +{% raw %} +```jsx +const DeleteButton = () => { + const resource = useResourceContext(); + const record = useRecordContext(); + const { + open, + isLoading, + handleDialogOpen, + handleDialogClose, + handleDelete, + } = useDeleteWithConfirmController({ redirect: 'list' }); -As for the developer experience, react-admin is constantly evolving to find the sweet spot between an intuitive API, power user features, not too much magic, and just enough documentation. The core team are the first testers of react-admin, and pay attention to the productivity, debuggability, discoverability, performance, and robustness of all the hooks and components. + return ( + + + + + ); +}; +``` +{% endraw %} -## Built On The Shoulders Of Giants +The fact that hook names often end with `Controller` is intentional and reflects the use of [the Model-View-Controller (MCV) pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) for complex components in react-admin. -Many excellent open-source libraries already address partial requirements of B2B apps: data fetching, forms, UI components, testing, etc. +- The Controller logic is handled by React hooks (e.g. `useListController`). +- The view logic is managed by React components (e.g. ``). +- The model logic is left to the developer, and react-admin simply defines the interface that the model must expose through its Providers. -Rather than reinventing the wheel, react-admin uses the best tools in each category (in terms of features, developer experience, active maintenance, documentation, user base), and provides a glue around these libraries. +React-admin exposes [dozens of hooks](./Reference.md#hooks) to assist you in building your own components. You can even construct an entire react-admin application without relying on the Material UI components and use a different UI kit if desired. This flexibility allows you to tailor the application to your specific needs and preferences. -In react-admin v4, these libraries are called react-query, react-router, react-hook-form, Material UI, testing-library, date-fns, and lodash. +## Context: Pull, Don't Push -When a new requirement arises, the react-admin teams always looks for an existing solution, and prefers integrating it rather than redeveloping it. +Communication between components can be challenging, especially in large React applications, where passing props down several levels can become cumbersome. React-admin addresses this issue using a pull model, where components expose props to their descendants via a context, and descendants can consume these props using custom hooks. -There is one constraint, though: all react-admin's dependencies must be compatible with the MIT licence. +Whenever a react-admin component fetches data or defines a callback, it creates a context and places the data and callback in it. -## Context: Pull, Don't Push +For instance, the `` component creates an `I18NProviderContext`, which exposes the `translate` function. All components in the application can utilize the `useTranslate` hook, which reads the `I18NProviderContext`, for translating labels and messages. -React-admin makes heavy use of React contexts. Whenever a component creates data or callbacks, it makes them available to descendants via a context. +```jsx +import { useTranslate } from 'react-admin'; -So when a component needs to access data or callbacks defined higher in the render tree, it can always find the context to get it. +export const MyHelloButton = ({ handleClick }) => { + const translate = useTranslate(); + return ( + + ); +}; +``` -For instance, to write a custom Field type for your Datagrid, use the `useRecordContext` hook to grab the current record value: +Similarly, the `` component fetches a record and exposes it via a `RecordContext`. Inside the `` component, you can use the `useRecordContext` hook to access the record data. For example, you can use it to display a map of the record's location. ```jsx -import * as React from "react"; -import PropTypes from 'prop-types'; import { useRecordContext } from 'react-admin'; +import { MapContainer, TileLayer, Marker } from 'react-leaflet'; -const TextField = (props) => { - const { source } = props; - const record = useRecordContext(props); - return {record[source]}; -} +const LocationField = ({ source }) => { + const record = useRecordContext(props); // use the RecordContext created by + if (!record) return null; -TextField.propTypes = { - label: PropTypes.string, - record: PropTypes.object, - source: PropTypes.string.isRequired, + return ( + + + + + ); }; -export default TextField; +const StoreShowPage = () => ( + {/* create a RecordContext */} + + + + + +) ``` -## Hooks +This approach eliminates the need for a dependency injection system and provides an elegant solution to access data and callbacks from higher levels in the render tree. -React-admin contexts aren't exposed directly. Instead, react-admin exposes hooks to access the context content. In addition, the framework also packages bits of reusable logic as hooks, to facilitate the customization of the UI of existing components without having to rewrite everything. Finally, hooks hide the implementation details of the framework, so that you can focus on the business logic. +So when you write a component that needs to access data or callbacks defined higher in the render tree, you can always find a context to get it. -So hooks are the primary way to read and change a react-admin application state. We use them in almost every react-admin component, and it's perfectly normal to use react-admin hooks in your own components. +Contexts are fundamental concepts in React Admin. If you are not familiar with them, don't hesitate to read the [React documentation on Context](https://react.dev/learn/passing-data-deeply-with-context). Understanding contexts will greatly enhance your understanding of how react-admin leverages them to create a powerful and flexible framework. -For instance, the `useRefresh` hook packages the logic to refetch the data currently displayed on the screen. Developers don't need to know how it works, just how to use it: +## Batteries Included But Removable -```jsx -import { useRefresh } from 'react-admin'; +React-admin allows you to build sophisticated web applications using only its built-in components, assuming that its design choices align with your needs. However, if you find that a component's existing capabilities don't meet your specific requirements, you're free to replace it with a custom component. + +For example, if [``](./SimpleShowLayout.md) doesn't allow you to arrange the details of a contact as depicted in the image below: + +![contact details](./img/atomic-crm.png) + +You can create and use your own layout component: + +{% raw %} +```tsx +export const ContactShow = () => ( + + + +); -const MyRefreshButton = () => { - const refresh = useRefresh(); +const ContactShowContent = () => { + const { record, isLoading } = useShowContext(); + if (isLoading || !record) return null; return ( - + + + + + + + + + {record.first_name} {record.last_name} + + + {record.title} at{' '} + + + + + + + + + + + + + + + + + + + ); }; ``` +{% endraw %} + +This particular example is sourced from [Atomic CRM](https://marmelab.com/react-admin-crm/#/contacts), one of the many [demo applications](./Demos.md) available for react-admin. + +Never hesitate to replace a react-admin component with one of your own design. React-admin does not aim to cover all possible use cases, instead, it provides hooks for incorporating custom components. After all, "It's just React"™. + +With react-admin, you'll never find yourself backed into a corner. + +## User Experience Is King + +React-admin has two distinct sets of users: + +- End users, who use the react-admin app in their browser +- Developers, who work with the react-admin code in their IDE + +We meticulously design both the User Experience (UX) and the Developer Experience (DX) for each feature. + +For the visual part, react-admin builds upon Material UI, which is a practical implementation of [Material Design](https://m3.material.io/). This design system is painstakingly constructed for web and mobile apps and serves as an excellent foundation for creating user-friendly, consistent user interfaces. However, it's only part of the story. + +We invest considerable time fine-tuning the UI to be as intuitive as possible. Small alignment discrepancies, screen flashes, and color inconsistencies are under constant scrutiny. We continually iterate based on customer feedback, working diligently to resolve any visual and animation issues that arise in real-world applications. + +By default, react-admin produces a purposefully bland user interface because we want the focus to be on the content rather than the aesthetics. + + + + +Regarding the developer experience, react-admin is always evolving to strike the right balance between an intuitive API, advanced features, a reasonable level of abstraction, and comprehensive documentation. The core team members are the initial testers of react-admin, focusing on productivity, debuggability, discoverability, performance, and reliability of all hooks and components. + +## Built On The Shoulders Of Giants + +Many excellent open-source libraries already address partial requirements of B2B apps: data fetching, forms, UI components, testing, etc. + +Rather than reinventing the wheel, react-admin uses the best tools in each category (in terms of features, developer experience, active maintenance, documentation, user base), and provides a glue around these libraries. + +In react-admin v4, these libraries are called [react-query](https://tanstack.com/query/v3), [react-router](https://reactrouter.com/en/main), [react-hook-form](https://react-hook-form.com/), [Material UI](https://mui.com/), [emotion](https://emotion.sh/docs/introduction), [testing-library](https://testing-library.com/docs/react-testing-library/intro), [date-fns](https://date-fns.org/), and [lodash](https://lodash.com/). + +When a new requirement arises, the react-admin teams always looks for an existing solution, and prefers integrating it rather than redeveloping it. + +There is one constraint, though: all react-admin's dependencies must be compatible with the [MIT license](https://github.com/marmelab/react-admin/blob/master/LICENSE.md). ## Minimal API Surface -Before adding a new hook or a new prop to an existing component, we always check if there isn't a simple way to implement the feature in pure React. If it's the case, then we don't add the new prop. We prefer to keep the react-admin API, code, test, and documentation simple. This choice is crucial to keep the learning curve acceptable, and maintenance burden low. +Before introducing a new hook or adding a new prop to an existing component, we always consider whether there's a straightforward way to implement the feature using pure React. If it's feasible, we opt not to add the new prop. Our goal is to maintain simplicity in the react-admin API, code, testing, and documentation. This decision is critical to ensuring a manageable learning curve and a low maintenance burden. -For instance, the `` component displays Field elements in a column. How can you put two fields in a single column? We could add a specific syntax allowing to specify the number of elements per column and per line. This would complicate the usage and documentation for simple use cases. Besides, it's doable in pure React, without any change in the react-admin core, e.g. by leveraging Material UI's `` component: +Take the `` component as an example, which displays Field elements in a column. Suppose you want to place two fields in a single column. We could introduce a specific syntax to indicate the number of elements per column and per line. However, this would overcomplicate the usage and documentation for simple use cases. Moreover, achieving this is quite doable in pure React, without necessitating any changes in the react-admin core. For instance, you can utilize Material UI's `` component: ```jsx import * as React from 'react'; @@ -197,51 +456,67 @@ const PostShow = () => ( ); ``` -We consider this snippet simple enough for a React developer, so we decided not to add support for multiple elements per line in the core. +We believe this code snippet is simple enough for a React developer, so we chose not to add core support for multiple elements per line. -If you don't find a particular feature in the react-admin documentation, it can mean it's doable quickly in pure React. +If you can't find a specific feature in the react-admin documentation, it's often because it can be quickly achieved using pure React. -## Principle Of Least Documentation +## Backward Compatibility Is More Important Than New Features + +Nobody enjoys updating their app's code simply because a foundational library has introduced a breaking change. React-admin makes a concerted effort to prevent such disruptions and the unnecessary time loss they cause for developers. + +Some components may have peculiar APIs, often for historical reasons. We prioritize maintaining backward compatibility as much as possible, occasionally at the expense of API consistency. + +The code for some components may seem unnecessarily complex. This usually happens when a component has to support both old and new syntaxes. + +Maintaining this backward compatibility requires a significant effort from the react-admin core team, but it pays off by saving substantial time for react-admin users. -No one reads docs. It's an unfortunate fact that we have learned to live with. +## Principle of Least Surprise -So when we design a new feature, we try to do it in the most intuitive way for developers. We keep the API minimal (see above). We copy the API of well-known libraries. We throw errors with helpful and explicit messages. We provide TypeScript types and JSDoc to help developers discover the API from within their IDE. We publish live examples with commented code. +Due to our emphasis on [composition](#composition), you should be able to combine react-admin components in various ways and expect them to work seamlessly (courtesy of to [contexts](#context-pull-dont-push)). We have a comprehensive test suite to ensure that the react-admin components interact well together. Moreover, TypeScript assists in identifying if you're using a component in a manner that isn't supported. -When we have to write documentation, it should contain: +These considerations lead to strong design choices in the react-admin code. -1. images/screencasts -2. code samples -3. text +One notable example relates to child inspection, which we strive to avoid whenever possible. An exception is the `` component, which inspects its Field children at runtime to determine the column headers. This practice has significant drawbacks: -In that order of importance. +- If a child is wrapped inside another component that doesn't follow the same API, the feature breaks +- Developers typically expect a component to affect its subtree, not its ancestors. Violating this expectation can lead to difficult-to-explain bugs. -## Inspecting Children Is Bad +We keep child inspection in `` because there is no superior alternative, but it's an uncommon exception. Every time we've implemented child inspection, we regretted it later. -Some components use child inspection for some features. For instance, the `` inspects its Field children at runtime to determine the column headers. This has serious drawbacks: +To minimize surprises, we also avoid using `React.cloneElement()` and refrain from passing props down the tree. -- If the child is wrapped inside another component that doesn't use the same API, the feature breaks -- Developers expect that a component affects its subtree, not its ancestors. This leads to inexplicable bugs. +## Principle Of Least Documentation + +No one reads docs. This is an unfortunate reality that we have come to terms with. + +Therefore, when designing a new feature, our priority is to make it as intuitive as possible for developers. We keep the API minimal ([see above](#minimal-api-surface)). We emulate the APIs of well-established libraries. We throw errors with clear and informative messages. To aid developers in discovering the API within their IDE, we provide TypeScript types and JSDoc. Furthermore, we publish live examples complemented by annotated code. -Every time we implemented child inspection, we regretted it afterward. We tend to avoid it at all costs, as well as using `React.cloneElement()`. +Despite this, given the extensive nature of react-admin, it inevitably comes with comprehensive documentation. We cover a wide variety of use cases, extending our documentation beyond mere usage instructions and API descriptions. To ensure that you find the information you need quickly, we frequently duplicate the same information in different places. We truly believe in the power of [serendipity](https://en.wikipedia.org/wiki/Serendipity). + +If you find this documentation overwhelming at first, don't fret. There's no need to read everything all at once. Start with the Introduction chapter of each section and examine the demo codes. Over time, you'll become familiar with the react-admin API, and finding the information you need will become a breeze. ## Monorepo - -React-admin is a *distribution* of several packages, each of which handles a specific feature. The packages are all located in the `packages/` directory. The most notable packages are: + +Whenever you import a react-admin component, it's sourced from the `react-admin` package: + +```jsx +import { List, Datagrid, TextField } from 'react-admin'; +``` + +But if you peek at [the react-admin source code](https://github.com/marmelab/react-admin) (which we encourage you to do), you will find imports like: + +```jsx +import { useListController } from 'ra-core'; +``` + +That's because the `react-admin` package simply re-exports components from internal packages. React-admin is a *distribution* of several packages, each dedicated to a specific feature. These packages can be found in [the `packages/` directory](https://github.com/marmelab/react-admin/tree/master/packages). Some of the more notable packages include: * `ra-core`: The core react-admin logic, without any UI. * `ra-ui-materialui`: The Material UI skin for react-admin. * `ra-data-*`: Data providers for various data backends. * `ra-language-*`: Interface translations for various languages. * `react-admin`: the standard distribution of react-admin - -You can build your own distribution of react-admin by combining different packages. - -## Backward Compatibility Is More Important Than New Features - -None of us like to update the code of our apps just because an underlying library has published a breaking change. React-admin does its best to avoid losing developers' time. -Some components may have a weird API. That's probably for historical reasons. We prefer to keep the backward compatibility as high as possible - sometimes at the cost of API consistency. +You can construct your own distribution of react-admin by combining various packages. Alternatively, you can import hooks and components directly from one of these packages if you don't want to import the entire react-admin distribution. -The code of some components may seem convoluted for no apparent reason. It's probably that the component has to support both the old and the new syntax. -This backward compatibility costs a lot in maintenance, and we try to reduce this cost by a good automated test coverage. diff --git a/docs/Features.md b/docs/Features.md index 24140c43662..d01f9b7bc8a 100644 --- a/docs/Features.md +++ b/docs/Features.md @@ -59,7 +59,7 @@ Which kind of API? **All kinds**. React-admin is backend agnostic. It doesn't ca Backend agnostic -React-admin ships with [more than 45 adapters](./DataProviderList.md) for popular API flavors, and gives you all the tools to build your own adapter. This works thanks to a powerful abstraction layer called the [Data Provider](./DataProviderIntroduction.md). +React-admin ships with [more than 50 adapters](./DataProviderList.md) for popular API flavors, and gives you all the tools to build your own adapter. This works thanks to a powerful abstraction layer called the [Data Provider](./DataProviderIntroduction.md). In a react-admin app, you don't write API Calls. Instead, you communicate with your API using a set of high-level functions, called "Data Provider methods". For instance, to fetch a list of posts, you call the `getList()` method, passing the resource name and the query parameters. diff --git a/docs/img/SPA-lifecycle.png b/docs/img/SPA-lifecycle.png new file mode 100644 index 00000000000..fe6b89f070b Binary files /dev/null and b/docs/img/SPA-lifecycle.png differ diff --git a/docs/img/atomic-crm.png b/docs/img/atomic-crm.png new file mode 100644 index 00000000000..b2aa640df92 Binary files /dev/null and b/docs/img/atomic-crm.png differ diff --git a/docs/img/components.webp b/docs/img/components.webp new file mode 100644 index 00000000000..0eed896bfa4 Binary files /dev/null and b/docs/img/components.webp differ diff --git a/docs/img/providers.png b/docs/img/providers.png new file mode 100644 index 00000000000..d8fb881cc5e Binary files /dev/null and b/docs/img/providers.png differ diff --git a/docs/navigation.html b/docs/navigation.html index aaf57a00f91..2523ebd1dbe 100644 --- a/docs/navigation.html +++ b/docs/navigation.html @@ -1,6 +1,7 @@
  • Ecosystem
  • -
  • Architecture
  • FAQ
  • Index