-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9620 from marmelab/source-context-fields
Leverage SourceContext in fields
- Loading branch information
Showing
38 changed files
with
428 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
layout: default | ||
title: "useFieldValue" | ||
--- | ||
|
||
# `useFieldValue` | ||
|
||
A hook that gets the value of a field of the current record. It gets the current record from the context or use the one provided as a prop. It supports deep sources such as `name.fr`. | ||
|
||
## Usage | ||
|
||
Here is an example `TextField` component: | ||
|
||
```tsx | ||
// In TextField.tsx | ||
import * as React from 'react'; | ||
import { useFieldValue, type FieldProps } from 'react-admin'; | ||
|
||
export const TextField = (props: FieldProps) => { | ||
const value = useFieldValue(props); | ||
return <span>{value}</span>; | ||
} | ||
|
||
// In PostShow.tsx | ||
import { Show, SimpleShowLayout } from 'react-admin'; | ||
import { TextField } from './TextField.tsx'; | ||
|
||
export const PostShow = () => ( | ||
<Show> | ||
<SimpleShowLayout> | ||
<TextField source="author.name" label="Author" /> | ||
</SimpleShowLayout> | ||
</Show> | ||
); | ||
``` | ||
|
||
## Params | ||
|
||
### `source` | ||
|
||
The name of the property on the record object that contains the value to display. Can be a deep path. | ||
|
||
```tsx | ||
import * as React from 'react'; | ||
import { useFieldValue } from 'react-admin'; | ||
|
||
export const CustomerCard = () => { | ||
const firstName = useFieldValue({ source: 'firstName' }); | ||
const lastName = useFieldValue({ source: 'lastName' }); | ||
return <span>{lastName} {firstName}</span>; | ||
} | ||
``` | ||
|
||
### `record` | ||
|
||
The record from which to read the value. Read from the `RecordContext` by default. | ||
|
||
|
||
```tsx | ||
import * as React from 'react'; | ||
import { useFieldValue, useGetOne } from 'react-admin'; | ||
|
||
export const CustomerCard = ({ id }: { id: string }) => { | ||
const { data } = useGetOne('customer', { id }); | ||
const firstName = useFieldValue({ source: 'firstName', record: data }); | ||
const lastName = useFieldValue({ source: 'lastName', record: data }); | ||
return <span>{lastName} {firstName}</span>; | ||
} | ||
``` | ||
|
||
### `defaultValue` | ||
|
||
The value to return when the record does not have a value for the specified `source`. | ||
|
||
```tsx | ||
import * as React from 'react'; | ||
import { useFieldValue } from 'react-admin'; | ||
|
||
export const CustomerStatus = () => { | ||
const status = useFieldValue({ source: 'status', defaultValue: 'active' }); | ||
return <span>{status}</span>; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import * as React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { useFieldValue, UseFieldValueOptions } from './useFieldValue'; | ||
import { RecordContextProvider } from '../controller'; | ||
import { SourceContextProvider } from '..'; | ||
|
||
describe('useFieldValue', () => { | ||
const Component = (props: UseFieldValueOptions) => { | ||
return <div>{useFieldValue(props) ?? 'None'}</div>; | ||
}; | ||
|
||
it('should return undefined if no record is available', async () => { | ||
render(<Component source="name" />); | ||
|
||
await screen.findByText('None'); | ||
}); | ||
|
||
it('should return the provided defaultValue if no record is available', async () => { | ||
render(<Component source="name" defaultValue="Molly Millions" />); | ||
|
||
await screen.findByText('Molly Millions'); | ||
}); | ||
|
||
it('should return the provided defaultValue if the record does not have a value for the source', async () => { | ||
render( | ||
<RecordContextProvider value={{ id: 123 }}> | ||
<Component source="name" defaultValue="Peter Riviera" /> | ||
</RecordContextProvider> | ||
); | ||
|
||
await screen.findByText('Peter Riviera'); | ||
}); | ||
|
||
it('should return the field value from the record in RecordContext', async () => { | ||
render( | ||
<RecordContextProvider value={{ name: 'John Wick' }}> | ||
<Component source="name" /> | ||
</RecordContextProvider> | ||
); | ||
|
||
await screen.findByText('John Wick'); | ||
}); | ||
|
||
it('should return the field value from the record in props', async () => { | ||
render( | ||
<RecordContextProvider value={{ id: 2, name: 'John Wick' }}> | ||
<Component | ||
source="name" | ||
record={{ id: 1, name: 'Johnny Silverhand' }} | ||
/> | ||
</RecordContextProvider> | ||
); | ||
|
||
await screen.findByText('Johnny Silverhand'); | ||
}); | ||
|
||
it('should return the field value from a deep path', async () => { | ||
render( | ||
<RecordContextProvider | ||
value={{ id: 2, name: { firstName: 'John', lastName: 'Wick' } }} | ||
> | ||
<Component source="name.firstName" /> | ||
</RecordContextProvider> | ||
); | ||
|
||
await screen.findByText('John'); | ||
}); | ||
|
||
it('should return the field value from the record inside a SourceContext', async () => { | ||
render( | ||
<RecordContextProvider | ||
value={{ | ||
id: 2, | ||
name: { fr: 'Neuromancien', en: 'Neuromancer' }, | ||
}} | ||
> | ||
<SourceContextProvider | ||
value={{ | ||
getSource(source) { | ||
return `${source}.fr`; | ||
}, | ||
getLabel: source => source, | ||
}} | ||
> | ||
<Component source="name" /> | ||
</SourceContextProvider> | ||
</RecordContextProvider> | ||
); | ||
|
||
await screen.findByText('Neuromancien'); | ||
}); | ||
}); |
Oops, something went wrong.