useListContext
Whenever ra-core displays a List, it creates a ListContext
to store the list data, as well as filters, pagination, sort state, and callbacks to update them.
The ListContext
is available to descendants of:
<ListBase>
,<ReferenceArrayFieldBase>
,<ReferenceManyFieldBase>
All descendant components can therefore access the list context, using the useListContext
hook.
Call useListContext
in a component, then use this component as a descendant of a list component.
// in src/posts/Aside.jsimport { useListContext } from 'ra-core';
export const Aside = () => { const { data, isPending } = useListContext(); if (isPending) return null; return ( <div> <h6>Posts stats</h6> <p> Total views: {data.reduce((sum, post) => sum + post.views, 0)} </p> </div> );};
// in src/posts/PostList.jsimport { ListBase } from 'ra-core';import Aside from './Aside';
export const PostList = () => ( <ListBase> <Aside /> {/* My list content */} </ListBase>);
Return Value
Section titled “Return Value”useListContext
returns an object with the following keys:
const { // Data data, // Array of the list records, e.g. [{ id: 123, title: 'hello world' }, { ... } total, // Total number of results for the current filters, excluding pagination. Useful to build the pagination controls, e.g. 23 meta, // Additional information about the list, like facets & statistics isPending, // Boolean, true until the data is available isFetching, // Boolean, true while the data is being fetched, false once the data is fetched isLoading, // Boolean, true until the data is fetched for the first time // Pagination page, // Current page. Starts at 1 perPage, // Number of results per page. Defaults to 25 setPage, // Callback to change the page, e.g. setPage(3) setPerPage, // Callback to change the number of results per page, e.g. setPerPage(25) hasPreviousPage, // Boolean, true if the current page is not the first one hasNextPage, // Boolean, true if the current page is not the last one // Sorting sort, // Sort object { field, order }, e.g. { field: 'date', order: 'DESC' } setSort, // Callback to change the sort, e.g. setSort({ field: 'name', order: 'ASC' }) // Filtering filterValues, // Dictionary of filter values, e.g. { title: 'lorem', nationality: 'fr' } displayedFilters, // Dictionary of displayed filters, e.g. { title: true, nationality: true } setFilters, // Callback to update the filters, e.g. setFilters(filters, displayedFilters) showFilter, // Callback to show one of the filters, e.g. showFilter('title', defaultValue) hideFilter, // Callback to hide one of the filters, e.g. hideFilter('title') // Record selection selectedIds, // Array listing the ids of the selected records, e.g. [123, 456] onSelect, // Callback to change the list of selected records, e.g. onSelect([456, 789]) onToggleItem, // Callback to toggle the record selection for a given id, e.g. onToggleItem(456) onUnselectItems, // Callback to clear the record selection, e.g. onUnselectItems(); // Misc defaultTitle, // Translated title based on the resource, e.g. 'Posts' resource, // Resource name, deduced from the location. e.g. 'posts' refetch, // Callback for fetching the list data again} = useListContext();
Declarative Version
Section titled “Declarative Version”useListContext
often forces you to create a new component just to access the list context. If you prefer a declarative approach based on render props, you can use the <WithListContext>
component instead:
import { WithListContext } from 'ra-core';
export const Aside = () => ( <WithListContext render={({ data, isPending }) => !isPending && ( <div> <h6>Posts stats</h6> <p> Total views: {data.reduce((sum, post) => sum + post.views, 0)} </p> </div> )} />);
Using setFilters
to Update Filters
Section titled “Using setFilters to Update Filters”The setFilters
method is used to update the filters. It takes three arguments:
filters
: an object containing the new filter valuesdisplayedFilters
: an object containing the new displayed filtersdebounced
: set to true to debounce the call to setFilters (false by default)
You can use it to update the filters in a custom filter component:
import { useState } from 'react';import { useListContext } from 'ra-core';
const CustomFilter = () => { const { filterValues, setFilters } = useListContext(); const [formValues, setFormValues] = useState(filterValues);
const handleChange = (event) => { setFormValues(formValues => ({ ...formValues, [event.target.name]: event.target.value })); };
const handleSubmit = (event) => { event.preventDefault(); setFilters(filterFormValues); };
return ( <form onSubmit={handleSubmit}> <input name="country" value={formValues.country} onChange={handleChange} /> <input name="city" value={formValues.city} onChange={handleChange} /> <input name="zipcode" value={formValues.zipcode} onChange={handleChange} /> <input type="submit">Filter</input> </form> );};
TypeScript
Section titled “TypeScript”The useListContext
hook accepts a generic parameter for the record type:
import { ListBase, useListContext } from 'ra-core';
type Post = { id: number; title: string; views: number;};
export const Aside = () => { const { data: posts, isPending } = useListContext<Post>(); if (isPending) return null; return ( <div> <h6>Posts stats</h6> <p> {/* TypeScript knows that posts is of type Post[] */} Total views: {posts.reduce((sum, post) => sum + post.views, 0)} </p> </div> );};
export const PostList = () => ( <ListBase> <Aside /> {/* My list content */} </ListBase>);
Recipes
Section titled “Recipes”You can find many usage examples of useListContext
in the documentation, including:
- Building a Custom Filter
- Building a Custom Sort Control
- Building a Custom Pagination Control
- Building a Custom List Layout
Tip: <ReferenceManyFieldBase>
, as well as other relationship-related components, also implement a ListContext
. That means you can use custom list components inside these components!