ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
168 lines (164 loc) • 5.71 kB
text/typescript
import { useContext, useMemo } from 'react';
import defaults from 'lodash/defaults';
import { ListContext } from './ListContext';
import { ListControllerResult } from './useListController';
import { RaRecord } from '../../types';
/**
* Hook to read the list controller props from the ListContext.
*
* Mostly used within a <ListContext.Provider> (e.g. as a descendent of <List>
* or <ListBase>).
*
* But you can also use it without a <ListContext.Provider>. In this case, it is up to you
* to pass all the necessary props (see the list below).
*
* The given props will take precedence over context values.
*
* @typedef {Object} ListControllerProps
* @prop {Object} data an array of the list records, e.g. [{ id: 123, title: 'hello world' }, { ... }]
* @prop {integer} total the total number of results for the current filters, excluding pagination. Useful to build the pagination controls. e.g. 23
* @prop {boolean} isFetching boolean that is true on mount, and false once the data was fetched
* @prop {boolean} isLoading boolean that is false until the data is available
* @prop {integer} page the current page. Starts at 1
* @prop {Function} setPage a callback to change the page, e.g. setPage(3)
* @prop {integer} perPage the number of results per page. Defaults to 25
* @prop {Function} setPerPage a callback to change the number of results per page, e.g. setPerPage(25)
* @prop {Object} sort a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
* @prop {Function} setSort a callback to change the sort, e.g. setSort({ field : 'name', order: 'ASC' })
* @prop {Object} filterValues a dictionary of filter values, e.g. { title: 'lorem', nationality: 'fr' }
* @prop {Function} setFilters a callback to update the filters, e.g. setFilters(filters, displayedFilters)
* @prop {Object} displayedFilters a dictionary of the displayed filters, e.g. { title: true, nationality: true }
* @prop {Function} showFilter a callback to show one of the filters, e.g. showFilter('title', defaultValue)
* @prop {Function} hideFilter a callback to hide one of the filters, e.g. hideFilter('title')
* @prop {Array} selectedIds an array listing the ids of the selected rows, e.g. [123, 456]
* @prop {Function} onSelect callback to change the list of selected rows, e.g. onSelect([456, 789])
* @prop {Function} onToggleItem callback to toggle the selection of a given record based on its id, e.g. onToggleItem(456)
* @prop {Function} onUnselectItems callback to clear the selection, e.g. onUnselectItems();
* @prop {string} defaultTitle the translated title based on the resource, e.g. 'Posts'
* @prop {string} resource the resource name, deduced from the location. e.g. 'posts'
*
* @returns {ListControllerResult} list controller props
*
* @see useListController for how it is filled
*
* @example // custom list view
*
* import { useListContext } from 'react-admin';
*
* const MyList = () => {
* const { data, isLoading } = useListContext();
* if (isLoading) {
* return <>Loading...</>;
* }
* return (
* <ul>
* {data.map(record => (
* <li key={record.id}>{record.name}</li>
* ))}
* </ul>
* );
* }
*
* @example // custom pagination
*
* import { useListContext } from 'react-admin';
* import { Button, Toolbar } from '@mui/material';
* import ChevronLeft from '@mui/icons-material/ChevronLeft';
* import ChevronRight from '@mui/icons-material/ChevronRight';
*
* const PrevNextPagination = () => {
* const { page, perPage, total, setPage } = useListContext();
* const nbPages = Math.ceil(total / perPage) || 1;
* return (
* nbPages > 1 &&
* <Toolbar>
* {page > 1 &&
* <Button color="primary" key="prev" onClick={() => setPage(page - 1)}>
* <ChevronLeft />
* Prev
* </Button>
* }
* {page !== nbPages &&
* <Button color="primary" key="next" onClick={() => setPage(page + 1)}>
* Next
* <ChevronRight />
* </Button>
* }
* </Toolbar>
* );
* }
*/
export const useListContext = <RecordType extends RaRecord = any>(
props?: any
): ListControllerResult<RecordType> => {
const context = useContext(ListContext);
// Props take precedence over the context
// @ts-ignore
return useMemo(
() =>
defaults(
{},
props != null ? extractListContextProps(props) : {},
context
),
[context, props]
);
};
/**
* Extract only the list controller props
*
* @param {Object} props Props passed to the useListContext hook
*
* @returns {ListControllerResult} List controller props
*/
const extractListContextProps = ({
sort,
data,
defaultTitle,
displayedFilters,
exporter,
filterValues,
hasCreate,
hideFilter,
isFetching,
isLoading,
onSelect,
onToggleItem,
onUnselectItems,
page,
perPage,
refetch,
resource,
selectedIds,
setFilters,
setPage,
setPerPage,
setSort,
showFilter,
total,
}) => ({
sort,
data,
defaultTitle,
displayedFilters,
exporter,
filterValues,
hasCreate,
hideFilter,
isFetching,
isLoading,
onSelect,
onToggleItem,
onUnselectItems,
page,
perPage,
refetch,
resource,
selectedIds,
setFilters,
setPage,
setPerPage,
setSort,
showFilter,
total,
});