Skip to content

Commit

Permalink
Merge pull request #9591 from marmelab/layout-no-props-cloning
Browse files Browse the repository at this point in the history
Remove injected props in Admin and Layout components
  • Loading branch information
adguernier committed Jan 24, 2024
2 parents a2f273f + 721ccca commit 76701a6
Show file tree
Hide file tree
Showing 70 changed files with 671 additions and 357 deletions.
44 changes: 42 additions & 2 deletions docs/Admin.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,15 @@ Layout components can be customized via props. For instance, you can pass a cust

```tsx
// in src/MyLayout.js
import type { ReactNode } from 'react';
import { Layout } from 'react-admin';
import MyMenu from './MyMenu';

export const MyLayout = (props) => <Layout {...props} menu={MyMenu} />;
export const MyLayout = ({ children }: { children: ReactNode }) => (
<Layout menu={MyMenu}>
{children}
</Layout>
);
```

Then, pass it to the `<Admin>` component as the `layout` prop:
Expand All @@ -617,7 +622,31 @@ const App = () => (

Refer to each layout component documentation to understand the props it accepts.

Finally, you can also pass a custom component as the `layout` prop. It must contain a `{children}` placeholder, where react-admin will render the page content. Check [the custom layout documentation](./Layout.md#writing-a-layout-from-scratch) for examples, and use the [default `<Layout>`](https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/layout/Layout.tsx) as a starting point.
Finally, you can also pass a custom component as the `layout` prop. Your custom layout will receive the page content as `children`, so it should render it somewhere.

```tsx
// in src/MyLayout.js
import type { ReactNode } from 'react';
export const MyLayout = ({ children }: { children: ReactNode }) => (
<div>
<h1>My App</h1>
<main>{children}</main>
</div>
);

// in src/App.js
import { Admin } from 'react-admin';
import { dataProvider } from './dataProvider';
import { MyLayout } from './MyLayout';

const App = () => (
<Admin dataProvider={dataProvider} layout={MyLayout}>
// ...
</Admin>
);
```

Check [the custom layout documentation](./Layout.md#writing-a-layout-from-scratch) for examples, and use the [default `<Layout>`](https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/layout/Layout.tsx) as a starting point.

## `loginPage`

Expand Down Expand Up @@ -878,6 +907,17 @@ const App = () => (
);
```

If you need to display this application title somewhere in your app, use the `useDefaultTitle` hook:

```tsx
import { useDefaultTitle } from 'react-admin';

const MyTitle = () => {
const defaultTitle = useDefaultTitle();
return <span>{defaultTitle}</span>; // My Custom Admin
};
```

## Adding Custom Pages

The [`children`](#children) prop of the `<Admin>` component define the routes of the application.
Expand Down
14 changes: 9 additions & 5 deletions docs/AppBar.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ Then, create a custom layout based on react-admin's `<Layout>`:
```jsx
// in src/MyLayout.js
import { Layout } from 'react-admin';

import { MyAppBar } from './MyAppBar';

export const MyLayout = props => <Layout {...props} appBar={MyAppBar} />;
export const MyLayout = ({ children }) => (
<Layout appBar={MyAppBar}>
{children}
</Layout>
);
```

Then pass this custom layout to the `<Admin>` component:
Expand Down Expand Up @@ -463,11 +466,12 @@ Then, use your custom app bar in a custom `<Layout>` component:
```jsx
// in src/MyLayout.js
import { Layout } from 'react-admin';

import { MyAppBar } from './MyAppBar';

export const MyLayout = (props) => (
<Layout {...props} appBar={MyAppBar} />
export const MyLayout = ({ children }) => (
<Layout appBar={MyAppBar}>
{children}
</Layout>
);
```

Expand Down
6 changes: 5 additions & 1 deletion docs/AppTheme.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,11 @@ const MySidebar = (props) => (
/>
);

const MyLayout = props => <Layout {...props} sidebar={MySidebar} />
const MyLayout = ({ children }) => (
<Layout sidebar={MySidebar}>
{children}
</Layout>
);
```
{% endraw %}

Expand Down
6 changes: 5 additions & 1 deletion docs/Architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@ The trade-off with this approach is that sometimes react-admin may require you t
import { Layout } from 'react-admin';
import { Menu } from './Menu';

export const Layout = (props) => <Layout {...props} menu={Menu} />;
export const Layout = ({ children }) => (
<Layout menu={Menu}>
{children}
</Layout>
);

// in src/App.js
import { Layout } from './Layout';
Expand Down
6 changes: 5 additions & 1 deletion docs/AuthRBAC.md
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,11 @@ const authProvider= {
}),
};

const CustomLayout = props => <Layout {...props} menu={Menu} />;
const CustomLayout = ({ children }) => (
<Layout menu={Menu}>
{children}
</Layout>
);

const App = () => (
<Admin dataProvider={dataProvider} authProvider={authProvider} layout={CustomLayout}>
Expand Down
6 changes: 5 additions & 1 deletion docs/Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,11 @@ const MyUserMenu = () => <UserMenu><MyLogoutButton /></UserMenu>;

const MyAppBar = () => <AppBar userMenu={<MyUserMenu />} />;

const MyLayout = (props) => <Layout {...props} appBar={MyAppBar} />;
const MyLayout = ({ children }) => (
<Layout appBar={MyAppBar}>
{children}
</Layout>
);

const App = () => (
<Admin layout={MyLayout}>
Expand Down
6 changes: 5 additions & 1 deletion docs/Buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,11 @@ To use this custom menu component, pass it to a custom Layout:
import { Layout } from 'react-admin';
import { Menu } from './Menu';

export const Layout = (props) => <Layout {...props} menu={Menu} />;
export const Layout = ({ children }) => (
<Layout menu={Menu}>
{children}
</Layout>
);
```

Then, use this layout in the `<Admin>` `layout` prop:
Expand Down
34 changes: 19 additions & 15 deletions docs/CheckForApplicationUpdate.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ Include this component in a custom layout:

```tsx
// in src/MyLayout.tsx
import { CheckForApplicationUpdate, Layout, LayoutProps } from 'react-admin';
import type { ReactNode } from 'react';
import { CheckForApplicationUpdate, Layout } from 'react-admin';

export const MyLayout = ({ children, ...props }: LayoutProps) => (
<Layout {...props}>
export const MyLayout = ({ children }: { children: ReactNode}) => (
<Layout>
{children}
<CheckForApplicationUpdate />
</Layout>
Expand Down Expand Up @@ -56,12 +57,13 @@ You can customize the interval between each check by providing the `interval` pr

```tsx
// in src/MyLayout.tsx
import { CheckForApplicationUpdate, Layout, LayoutProps } from 'react-admin';
import type { ReactNode } from 'react';
import { CheckForApplicationUpdate, Layout } from 'react-admin';

const HALF_HOUR = 30 * 60 * 1000;

export const MyLayout = ({ children, ...props }: LayoutProps) => (
<Layout {...props}>
export const MyLayout = ({ children }: { children: ReactNode}) => (
<Layout>
{children}
<CheckForApplicationUpdate interval={HALF_HOUR} />
</Layout>
Expand All @@ -74,10 +76,11 @@ You can dynamically disable the automatic application update detection by provid

```tsx
// in src/MyLayout.tsx
import { CheckForApplicationUpdate, Layout, LayoutProps } from 'react-admin';
import type { ReactNode } from 'react';
import { CheckForApplicationUpdate, Layout } from 'react-admin';

export const MyLayout = ({ children, ...props }: LayoutProps) => (
<Layout {...props}>
export const MyLayout = ({ children }: { children: ReactNode}) => (
<Layout>
{children}
<CheckForApplicationUpdate disabled={process.env.NODE_ENV !== 'production'} />
</Layout>
Expand All @@ -91,7 +94,7 @@ Note that you must wrap your component with `forwardRef`.

```tsx
// in src/MyLayout.tsx
import { forwardRef } from 'react';
import { forwardRef, ReactNode } from 'react';
import { Layout, CheckForApplicationUpdate } from 'react-admin';

const CustomAppUpdatedNotification = forwardRef((props, ref) => (
Expand All @@ -112,8 +115,8 @@ const CustomAppUpdatedNotification = forwardRef((props, ref) => (
</Alert>
));

const MyLayout = ({ children, ...props }) => (
<Layout {...props}>
const MyLayout = ({ children }: { children: ReactNode}) => (
<Layout>
{children}
<CheckForApplicationUpdate notification={<CustomAppUpdatedNotification />}/>
</Layout>
Expand Down Expand Up @@ -163,12 +166,13 @@ You can customize the URL fetched to detect updates by providing the `url` prop.

```tsx
// in src/MyLayout.tsx
import { CheckForApplicationUpdate, Layout, LayoutProps } from 'react-admin';
import type { ReactNode } from 'react';
import { CheckForApplicationUpdate, Layout } from 'react-admin';

const MY_APP_ROOT_URL = 'https://admin.mycompany.com';

export const MyLayout = ({ children, ...props }: LayoutProps) => (
<Layout {...props}>
export const MyLayout = ({ children }: { children: ReactNode}) => (
<Layout>
{children}
<CheckForApplicationUpdate url={MY_APP_ROOT_URL} />
</Layout>
Expand Down
7 changes: 4 additions & 3 deletions docs/CreateReactApp.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ To enable it, start by creating a custom layout:

```tsx
// in src/admin/MyLayout.tsx
import { CheckForApplicationUpdate, Layout, LayoutProps } from 'react-admin';
import type { ReactNode } from 'react';
import { CheckForApplicationUpdate, Layout } from 'react-admin';

export const MyLayout = ({ children, ...props }: LayoutProps) => (
<Layout {...props}>
export const MyLayout = ({ children }: { children: ReactNode}) => (
<Layout>
{children}
<CheckForApplicationUpdate />
</Layout>
Expand Down
6 changes: 5 additions & 1 deletion docs/CustomRoutes.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@ Next, pass the custom menu to a custom `<Layout>` component:
import { Layout } from 'react-admin';
import { MyMenu } from './MyMenu';

export const MyLayout = (props) => <Layout {...props} menu={MyMenu} />;
export const MyLayout = ({ children }) => (
<Layout menu={MyMenu}>
{children}
</Layout>
);
```

Finally, pass the custom `<Layout>` component to `<Admin>`:
Expand Down
8 changes: 4 additions & 4 deletions docs/DataProviders.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ To enable these devtools, add the `<ReactQueryDevtools>` component to a custom L
import { Layout } from 'react-admin';
import { ReactQueryDevtools } from 'react-query/devtools';

export const MyLayout = props => (
<>
<Layout {...props} />
export const MyLayout = ({ children }) => (
<Layout>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</>
</Layout>
);
```

Expand Down
6 changes: 4 additions & 2 deletions docs/Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -1191,8 +1191,10 @@ import { MenuLive } from '@react-admin/ra-realtime';

import { PostList, PostShow, PostEdit, realTimeDataProvider } from '.';

const CustomLayout = (props) => (
<Layout {...props} menu={MenuLive} />
const CustomLayout = ({ children }) => (
<Layout menu={MenuLive}>
{children}
</Layout>
);

const MyReactAdmin = () => (
Expand Down
6 changes: 4 additions & 2 deletions docs/IconMenu.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ import { AppLocationContext } from '@react-admin/ra-navigation';

import { MyMenu } from './MyMenu';

export const MyLayout = (props) => (
export const MyLayout = ({ children }) => (
<AppLocationContext>
<Layout {...props} menu={MyMenu} />
<Layout menu={MyMenu}>
{children}
</Layout>
</AppLocationContext>
);
```
Expand Down
Loading

0 comments on commit 76701a6

Please sign in to comment.