Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BC Break] Add ReferenceOneField #7060

Merged
merged 6 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,29 @@ export const PostList = () => (
);
```

## No More Props Injection In `<ReferenceField>`

`<ReferenceField>` creates a `RecordContext` for the reference record, and this allows using any of react-admin's Field components. It also used to pass many props to the underlying component (including the current `record`), but this is no longer the case. If you need to access the `record` in a child of `<ReferenceField>`, you need to use the `useRecordContext` hook instead.

```diff
const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="title" />
<ReferenceField source="author_id" reference="users">
<NameField />
</ReferenceField>
</SimpleShowLayout>
</Show>
);

-const NameField = ({ record }) => {
+const NameField = () => {
+ const { record } = useRecordContext();
return <span>{record?.name}</span>;
};
```

## `useListContext` No Longer Returns An `ids` Prop

The `ListContext` used to return two props for the list data: `data` and `ids`. To render the list data, you had to iterate over the `ids`.
Expand Down
414 changes: 414 additions & 0 deletions docs/FieldsForRelationships.md

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion docs/navigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,12 @@
<li {% if page.path contains 'CreateEdit.md' %} class="active" {% endif %}><a class="nav-link" href="./CreateEdit.html"><code>&lt;Create&gt;</code> and <code>&lt;Edit&gt;</code> Views</a></li>
</ul>

<ul><div>Fields and Inputs</div>
<ul><div>Fields</div>
<li {% if page.path contains 'FieldsForRelationships.md' %} class="active" {% endif %}><a class="nav-link" href="./FieldsForRelationships.html">Fields for Relationships</a></li>
<li {% if page.path contains 'Fields.md' %} class="active" {% endif %}><a class="nav-link" href="./Fields.html"><code>&lt;Field&gt;</code> Components</a></li>
</ul>

<ul><div>Inputs</div>
<li {% if page.path contains 'Inputs.md' %} class="active" {% endif %}><a class="nav-link" href="./Inputs.html"><code>&lt;Input&gt;</code> Components</a></li>
</ul>

Expand Down
4 changes: 2 additions & 2 deletions examples/crm/src/companies/CompanyAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { styled } from '@mui/material/styles';
import { Avatar } from '@mui/material';
import clsx from 'clsx';
import { useRecordContext } from 'react-admin';

import { Company } from '../types';

Expand Down Expand Up @@ -34,12 +35,11 @@ const StyledAvatar = styled(Avatar)({
});

export const CompanyAvatar = ({
record,
size = 'large',
}: {
record?: Company;
size?: 'small' | 'large';
}) => {
const record = useRecordContext<Company>();
if (!record) return null;
return (
<StyledAvatar
Expand Down
2 changes: 1 addition & 1 deletion examples/crm/src/companies/CompanyCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const CompanyCard = ({ record }: { record: Company }) => {
>
<Paper className={classes.paper} elevation={elevation}>
<div className={classes.identity}>
<CompanyAvatar record={record} />
<CompanyAvatar />
<div className={classes.name}>
<Typography variant="subtitle2">
{record.name}
Expand Down
22 changes: 9 additions & 13 deletions examples/crm/src/companies/CompanyEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
SimpleForm,
TextInput,
SelectInput,
useRecordContext,
required,
} from 'react-admin';
import { Box, CardContent, Divider } from '@mui/material';
Expand Down Expand Up @@ -84,19 +83,16 @@ export const CompanyEdit = () => {
);
};

const CustomLayout = (props: any) => {
const record = useRecordContext(props);
return (
<CardContent>
<Box display="flex">
<LogoField record={record as any} />
<Box ml={2} flex="1" maxWidth={796}>
{props.children}
</Box>
const CustomLayout = (props: any) => (
<CardContent>
<Box display="flex">
<LogoField />
<Box ml={2} flex="1" maxWidth={796}>
{props.children}
</Box>
</CardContent>
);
};
</Box>
</CardContent>
);

const CustomDivider = () => (
<Box mb={2}>
Expand Down
2 changes: 1 addition & 1 deletion examples/crm/src/companies/CompanyShow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const CompanyShowContent = () => {
<Card>
<CardContent>
<Box display="flex" mb={1}>
<LogoField record={record as any} />
<LogoField />
<Box ml={2} flex="1">
<Typography variant="h5">
{record.name}
Expand Down
4 changes: 2 additions & 2 deletions examples/crm/src/companies/LogoField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import { useRecordContext } from 'react-admin';

const PREFIX = 'LogoField';

Expand All @@ -19,14 +20,13 @@ const sizeInPixel = {
};

export const LogoField = ({
record,
source,
size = 'medium',
}: {
record?: { logo: string; name: string };
source?: string;
size?: 'small' | 'medium';
}) => {
const record = useRecordContext<{ logo: string; name: string }>();
if (!record) return null;
return (
<StyledImage
Expand Down
2 changes: 1 addition & 1 deletion examples/crm/src/contacts/ContactAside.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const ContactAside = ({ record, link = 'edit' }: any) => (
<Box mb={3}>
<Typography variant="subtitle2">Tags</Typography>
<Divider />
<TagsListEdit record={record} />
<TagsListEdit />
</Box>

<ReferenceManyField
Expand Down
18 changes: 14 additions & 4 deletions examples/crm/src/contacts/TagsList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import { ReferenceArrayField, SingleFieldList, ChipField } from 'react-admin';
import {
ReferenceArrayField,
SingleFieldList,
ChipField,
useRecordContext,
} from 'react-admin';

import { Contact } from '../types';

Expand All @@ -16,15 +21,20 @@ const StyledReferenceArrayField = styled(ReferenceArrayField)({
},
});

const ColoredChipField = ({ record, ...props }: any) =>
record ? (
const ColoredChipField = (props: any) => {
const record = useRecordContext();
if (!record) {
return null;
}
return (
<ChipField
record={record}
{...props}
style={{ backgroundColor: record.color, border: 0 }}
component="span"
/>
) : null;
);
};

export const TagsList = ({ record }: { record: Contact }) => {
if (!record) return null;
Expand Down
10 changes: 5 additions & 5 deletions examples/crm/src/contacts/TagsListEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
useUpdate,
useGetList,
Identifier,
useRecordContext,
} from 'react-admin';
import {
Chip,
Expand All @@ -26,7 +27,8 @@ import EditIcon from '@mui/icons-material/Edit';
import { colors } from '../tags/colors';
import { Contact, Tag } from '../types';

export const TagsListEdit = ({ record }: { record: Contact }) => {
export const TagsListEdit = () => {
const record = useRecordContext<Contact>();
const [open, setOpen] = useState(false);
const [newTagName, setNewTagName] = useState('');
const [newTagColor, setNewTagColor] = useState(colors[0]);
Expand All @@ -42,9 +44,7 @@ export const TagsListEdit = ({ record }: { record: Contact }) => {
const { data: tags, isLoading: isLoadingRecordTags } = useGetMany<Tag>(
'tags',
{ ids: record.tags },
{
enabled: record.tags && record.tags.length > 0,
}
{ enabled: record && record.tags && record.tags.length > 0 }
);
const [update] = useUpdate<Contact>();
const [create] = useCreate<Tag>();
Expand Down Expand Up @@ -123,7 +123,7 @@ export const TagsListEdit = ({ record }: { record: Contact }) => {
);
};

if (!isLoadingRecordTags || isLoadingAllTags) return null;
if (isLoadingRecordTags || isLoadingAllTags) return null;
return (
<>
{tags?.map(tag => (
Expand Down
23 changes: 12 additions & 11 deletions examples/demo/src/visitors/ColoredNumberField.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import * as React from 'react';
import { NumberField, NumberFieldProps } from 'react-admin';
import { useRecordContext, NumberField, NumberFieldProps } from 'react-admin';

const ColoredNumberField = (props: NumberFieldProps) =>
props.record && props.source ? (
props.record[props.source] > 500 ? (
<span style={{ color: 'red' }}>
<NumberField {...props} />
</span>
) : (
<NumberField {...props} />
)
) : null;
const ColoredNumberField = (props: NumberFieldProps) => {
const record = useRecordContext(props);
if (!record || !props.source) {
return null;
}
return record[props.source] > 500 ? (
<NumberField {...props} sx={{ color: 'red' }} />
) : (
<NumberField {...props} />
);
};

ColoredNumberField.defaultProps = NumberField.defaultProps;

Expand Down
17 changes: 11 additions & 6 deletions examples/demo/src/visitors/CustomerLinkField.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import * as React from 'react';
import { Link, FieldProps } from 'react-admin';
import { Link, FieldProps, useRecordContext } from 'react-admin';

import FullNameField from './FullNameField';
import { Customer } from '../types';

const CustomerLinkField = (props: FieldProps<Customer>) =>
props.record ? (
<Link to={`/customers/${props.record.id}`}>
<FullNameField {...props} />
const CustomerLinkField = (props: FieldProps<Customer>) => {
const record = useRecordContext();
if (!record) {
return null;
}
return (
<Link to={`/customers/${record.id}`}>
<FullNameField />
</Link>
) : null;
);
};

CustomerLinkField.defaultProps = {
source: 'customer_id',
Expand Down
6 changes: 3 additions & 3 deletions examples/demo/src/visitors/FullNameField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import { styled } from '@mui/material/styles';
import { memo } from 'react';

import { FieldProps } from 'react-admin';
import { FieldProps, useRecordContext } from 'react-admin';
import AvatarField from './AvatarField';
import { Customer } from '../types';

Expand Down Expand Up @@ -32,8 +32,8 @@ interface Props extends FieldProps<Customer> {
}

const FullNameField = (props: Props) => {
const { record, size } = props;

const { size } = props;
const record = useRecordContext<Customer>();
return record ? (
<Root className={classes.root}>
<AvatarField
Expand Down
1 change: 1 addition & 0 deletions packages/ra-core/src/controller/field/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './getResourceLinkPath';
export * from './useReferenceArrayFieldController';
export * from './useReferenceManyFieldController';
export * from './useReferenceOneFieldController';
Loading