Skip to content

Commit

Permalink
Merge pull request #5886 from marmelab/reference-array-input-list-con…
Browse files Browse the repository at this point in the history
…text

Add ListContext to ReferenceArrayInput
  • Loading branch information
fzaninotto committed Feb 24, 2021
2 parents 64e8471 + 59e4097 commit c4be146
Show file tree
Hide file tree
Showing 13 changed files with 877 additions and 306 deletions.
24 changes: 23 additions & 1 deletion docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1406,7 +1406,7 @@ http://myapi.com/tags?id=[1,23,4]
http://myapi.com/tags?page=1&perPage=25
```

Once it receives the deduplicated reference resources, this component delegates rendering to a subcomponent, to which it passes the possible choices as the `choices` attribute.
Once it receives the deduplicated reference resources, this component delegates rendering to a subcomponent, by providing the possible choices through the `ReferenceArrayInputContext`. This context value can be accessed with the [`useReferenceArrayInputContext`](#usereferencearrayinputcontext) hook.

This means you can use `<ReferenceArrayInput>` with [`<SelectArrayInput>`](#selectarrayinput), or with the component of your choice, provided it supports the `choices` attribute.

Expand Down Expand Up @@ -1477,8 +1477,30 @@ You can tweak how this component fetches the possible values using the `perPage`
```
{% endraw %}

In addition to the `ReferenceArrayInputContext`, `<ReferenceArrayInput>` also sets up a `ListContext` providing access to the records from the reference resource in a similar fashion to that of the `<List>` component. This `ListContext` value is accessible with the [`useListContext`](/List.md#uselistcontext) hook.

`<ReferenceArrayInput>` also accepts the [common input props](./Inputs.md#common-input-props).

### `useReferenceArrayInputContext`

The [`<ReferenceArrayInput>`](#referencearrayinput) component take care of fetching the data, and put that data in a context called `ReferenceArrayInputContext` so that it’s available for its descendants. This context also stores filters, pagination, sort state, and provides callbacks to update them.

Any component decendent of `<ReferenceArryInput>` can grab information from the `ReferenceArrayInputContext` using the `useReferenceArrayInputContext` hook. Here is what it returns:

```js
const {
choices, // An array of records matching both the current input value and the filters
error, // A potential error that may have occured while fetching the data
warning, // A potential warning regarding missing references
loaded, // boolean that is false until the data is available
loading, // boolean that is true on mount, and false once the data was fetched
setFilter, // a callback to update the filters, e.g. setFilters({ q: 'query' })
setPagination, // a callback to change the pagination, e.g. setPagination({ page: 2, perPage: 50 })
setSort, // a callback to change the sort, e.g. setSort({ field: 'name', order: 'DESC' })
setSortForList, // a callback to set the sort with the same signature as the one from the ListContext. This is required to avoid breaking backward compatibility and will be removed in v4
} = useReferenceArrayInputContext();
```

### `<ReferenceInput>`

Use `<ReferenceInput>` for foreign-key values, for instance, to edit the `post_id` of a `comment` resource. This component fetches the related record (using `dataProvider.getMany()`) as well as possible choices (using `dataProvider.getList()` in the reference resource), then delegates rendering to a subcomponent, to which it passes the possible choices as the `choices` attribute.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import usePaginationState from '../usePaginationState';
import useSelectionState from '../useSelectionState';
import useSortState from '../useSortState';
import { useResourceContext } from '../../core';
import { indexById } from '../../util/indexById';

interface Option {
basePath: string;
Expand Down Expand Up @@ -239,12 +240,4 @@ const useReferenceArrayFieldController = (
};
};

const indexById = (records: Record[] = []): RecordMap =>
records
.filter(r => typeof r !== 'undefined')
.reduce((prev, current) => {
prev[current.id] = current;
return prev;
}, {});

export default useReferenceArrayFieldController;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createContext } from 'react';
import { PaginationPayload, Record, SortPayload } from '../../types';

/**
* Context which provides access to the useReferenceArrayInput features.
*
* @example
* const ReferenceArrayInput = ({ children }) => {
* const controllerProps = useReferenceArrayInputController();
* return (
* <ReferenceArrayInputContextProvider value={controllerProps}>
* {children}
* </ReferenceArrayInputContextProvider>
* )
* }
*/
export const ReferenceArrayInputContext = createContext(undefined);

export interface ReferenceArrayInputContextValue {
choices: Record[];
error?: any;
warning?: any;
loading: boolean;
loaded: boolean;
setFilter: (filter: any) => void;
setPagination: (pagination: PaginationPayload) => void;
setSort: (sort: SortPayload) => void;
setSortForList: (sort: string, order?: string) => void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';
import { ReactNode } from 'react';
import {
ReferenceArrayInputContext,
ReferenceArrayInputContextValue,
} from './ReferenceArrayInputContext';

/**
* Provider for the context which provides access to the useReferenceArrayInput features.
*
* @example
* const ReferenceArrayInput = ({ children }) => {
* const controllerProps = useReferenceArrayInputController();
* return (
* <ReferenceArrayInputContextProvider value={controllerProps}>
* {children}
* </ReferenceArrayInputContextProvider>
* )
* }
*/
export const ReferenceArrayInputContextProvider = ({
children,
value,
}: {
children: ReactNode;
value: ReferenceArrayInputContextValue;
}) => (
<ReferenceArrayInputContext.Provider value={value}>
{children}
</ReferenceArrayInputContext.Provider>
);
Loading

0 comments on commit c4be146

Please sign in to comment.