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] Change setSort signature to make it consistent acrosse components #7065

Merged
merged 3 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
31 changes: 31 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,37 @@ const CommentGrid = () => {
};
```

## `setSort()` Signature Changed

Some react-admin components have access to a `setSort()` callback to sort the current list of items. This callback is also presenty in the `ListContext`. Its signature has changed:

```diff
-setSort(field: string, order: 'ASC' | 'DESC');
+setSort({ field: string, order: 'ASC' | 'DESC' });
```

This impacts your code if you built a custom sort component:

```diff
const SortButton = () => {
const { currentSort, setSort } = useListContext();
const handleChangeSort = (event) => {
const field = event.currentTarget.dataset.sort;
- setSort(
- field,
- field === currentSort.field ? inverseOrder(currentSort.order) : 'ASC',
- });
+ setSort({
+ field,
+ order: field === currentSort.field ? inverseOrder(currentSort.order) : 'ASC',
+ });
setAnchorEl(null);
};

// ...
};
```

## Removed Reducers

If your code used `useSelector` to read the react-admin application state, it will likely break. React-admin v4 uses Redux much less than v3, and the shape of the Redux state has changed.
Expand Down
3 changes: 1 addition & 2 deletions docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2055,7 +2055,7 @@ In addition to the `ReferenceArrayInputContext`, `<ReferenceArrayInput>` also se

### `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.
The [`<ReferenceArrayInput>`](#referencearrayinput) component takes care of fetching the data, and putting 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 descendant of `<ReferenceArrayInput>` can grab information from the `ReferenceArrayInputContext` using the `useReferenceArrayInputContext` hook. Here is what it returns:

Expand All @@ -2069,7 +2069,6 @@ const {
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();
```

Expand Down
10 changes: 4 additions & 6 deletions docs/ListTutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ import { useListSortContext, useTranslate } from 'react-admin';

const SortButton = ({ fields }) => {
// currentSort is an object { field, order } containing the current sort
// setSort is a callback (field, order) => void allowing to change the sort field and order
// setSort is a callback ({ field, order }) => void allowing to change the sort field and order
const { currentSort, setSort } = useListSortContext();
// rely on the translations to display labels like 'Sort by sales descending'
const translate = useTranslate();
Expand All @@ -561,12 +561,10 @@ const SortButton = ({ fields }) => {
};
const handleChangeSort = (event) => {
const field = event.currentTarget.dataset.sort;
setSort(
setSort({
field,
field === currentSort.field
? inverseOrder(currentSort.order)
: 'ASC'
);
order: field === currentSort.field ? inverseOrder(currentSort.order) : 'ASC'
});
setAnchorEl(null);
};

Expand Down
2 changes: 1 addition & 1 deletion docs/useList.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ const {
setPerPage, // a callback to change the number of results per page, e.g. setPerPage(25)
// sorting
currentSort, // a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
setSort, // a callback to change the sort, e.g. setSort('name', 'ASC')
setSort, // a callback to change the sort, e.g. setSort({ field: 'name', order: 'ASC' })
// filtering
filterValues, // a dictionary of filter values, e.g. { title: 'lorem', nationality: 'fr' }
displayedFilters, // a dictionary of the displayed filters, e.g. { title: true, nationality: true }
Expand Down
2 changes: 1 addition & 1 deletion docs/useListContext.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const {
setPerPage, // a callback to change the number of results per page, e.g. setPerPage(25)
// sorting
currentSort, // a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
setSort, // a callback to change the sort, e.g. setSort('name', 'ASC')
setSort, // a callback to change the sort, e.g. setSort({ field: 'name', orfer: 'ASC' })
// filtering
filterValues, // a dictionary of filter values, e.g. { title: 'lorem', nationality: 'fr' }
displayedFilters, // a dictionary of the displayed filters, e.g. { title: true, nationality: true }
Expand Down
2 changes: 1 addition & 1 deletion docs/useListController.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const {
setPerPage, // a callback to change the number of results per page, e.g. setPerPage(25)
// sorting
currentSort, // a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
setSort, // a callback to change the sort, e.g. setSort('name', 'ASC')
setSort, // a callback to change the sort, e.g. setSort({ field: 'name', order: 'ASC' })
// filtering
filterValues, // a dictionary of filter values, e.g. { title: 'lorem', nationality: 'fr' }
displayedFilters, // a dictionary of the displayed filters, e.g. { title: true, nationality: true }
Expand Down
1 change: 1 addition & 0 deletions packages/ra-core/src/actions/listActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Identifier } from '../types';

export const CRUD_CHANGE_LIST_PARAMS = 'RA/CRUD_CHANGE_LIST_PARAMS';

// Serializable list params (for the query string)
export interface ListParams {
sort: string;
order: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ export const useReferenceManyFieldController = (
});

// sort logic
const { sort, setSort: setSortObject } = useSortState(initialSort);
const { sort, setSort: setSortState } = useSortState(initialSort);
const setSort = useCallback(
(field: string, order: string = 'ASC') => {
setSortObject({ field, order });
(sort: SortPayload) => {
setSortState(sort);
setPage(1);
},
[setPage, setSortObject]
[setPage, setSortState]
);

// selection logic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,4 @@ export interface ReferenceArrayInputContextValue<
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
Expand Up @@ -38,7 +38,6 @@ const extractReferenceArrayInputContextProps = <
setFilter,
setPagination,
setSort,
setSortForList,
warning,
}: T) => ({
choices,
Expand All @@ -48,6 +47,5 @@ const extractReferenceArrayInputContextProps = <
setFilter,
setPagination,
setSort,
setSortForList,
warning,
});
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ describe('useReferenceArrayInputController', () => {
const children = ({
setPage,
setPerPage,
setSortForList,
setSort,
}): React.ReactElement => {
const handleSetPage = () => {
setPage(2);
Expand All @@ -703,7 +703,7 @@ describe('useReferenceArrayInputController', () => {
setPerPage(50);
};
const handleSetSort = () => {
setSortForList('name', SORT_ASC);
setSort({ field: 'name', order: SORT_ASC });
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,26 +123,22 @@ export const useReferenceArrayInputController = <

// sort logic
const sortRef = useRef(initialSort);
const { sort, setSort } = useSortState(initialSort);
const { sort, setSort: setSortState } = useSortState(initialSort);

// ReferenceArrayInput.setSort had a different signature than the one from ListContext.
// In order to not break backward compatibility, we added this temporary setSortForList in the
// ReferenceArrayInputContext
// FIXME remove in 4.0
const setSortForList = useCallback(
(field: string, order: string = 'ASC') => {
setSort({ field, order });
const setSort = useCallback(
(sort: SortPayload) => {
setSortState(sort);
setPage(1);
},
[setPage, setSort]
[setPage, setSortState]
);

// Ensure sort can be updated through props too, not just by using the setSort function
useEffect(() => {
if (!isEqual(initialSort, sortRef.current)) {
setSort(initialSort);
setSortState(initialSort);
}
}, [setSort, initialSort]);
}, [setSortState, initialSort]);

// Ensure pagination can be updated through props too, not just by using the setPagination function
const paginationRef = useRef({ initialPage, initialPerPage });
Expand Down Expand Up @@ -285,7 +281,6 @@ export const useReferenceArrayInputController = <
setPagination,
setPerPage,
setSort,
setSortForList,
showFilter,
warning: dataStatus.warning,
total,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ export const useReferenceInputController = <RecordType extends Record = Record>(
} = usePaginationState({ page: initialPage, perPage: initialPerPage });

// sort logic
const { sort, setSort: setSortObject } = useSortState(sortOverride);
const { sort, setSort: setSortState } = useSortState(sortOverride);
const setSort = useCallback(
(field: string, order: string = 'ASC') => {
setSortObject({ field, order });
(sort: SortPayload) => {
setSortState(sort);
setPage(1);
},
[setPage, setSortObject]
[setPage, setSortState]
);

// filter logic
Expand Down Expand Up @@ -208,7 +208,7 @@ export const useReferenceInputController = <RecordType extends Record = Record>(
pagination,
setPagination,
sort,
setSort: setSortObject,
setSort,
warning: dataStatus.warning,
};
};
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/controller/list/ListContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ListControllerResult } from './useListController';
* @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} currentSort a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
* @prop {Function} setSort a callback to change the sort, e.g. setSort('name', 'ASC')
* @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 }
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/controller/list/ListSortContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ListControllerResult } from './useListController';
*
* @typedef {Object} ListSortContextValue
* @prop {Object} currentSort a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
* @prop {Function} setSort a callback to change the sort, e.g. setSort('name', 'ASC')
* @prop {Function} setSort a callback to change the sort, e.g. setSort({ field: 'name', order: 'ASC' })
* @prop {string} resource the resource name, deduced from the location. e.g. 'posts'
*
* @typedef Props
Expand Down
12 changes: 5 additions & 7 deletions packages/ra-core/src/controller/list/queryReducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ describe('Query Reducer', () => {
describe('SET_PAGE action', () => {
it('should update the page', () => {
const updatedState = queryReducer(
{
page: 1,
},
{ page: 1 },
{
type: 'SET_PAGE',
payload: 2,
Expand Down Expand Up @@ -188,7 +186,7 @@ describe('Query Reducer', () => {
{},
{
type: 'SET_SORT',
payload: { sort: 'foo' },
payload: { field: 'foo' },
}
);
expect(updatedState).toEqual({
Expand All @@ -202,7 +200,7 @@ describe('Query Reducer', () => {
{},
{
type: 'SET_SORT',
payload: { sort: 'foo', order: SORT_DESC },
payload: { field: 'foo', order: SORT_DESC },
}
);
expect(updatedState).toEqual({
Expand All @@ -220,7 +218,7 @@ describe('Query Reducer', () => {
},
{
type: 'SET_SORT',
payload: { sort: 'foo' },
payload: { field: 'foo' },
}
);
expect(updatedState).toEqual({
Expand All @@ -238,7 +236,7 @@ describe('Query Reducer', () => {
},
{
type: 'SET_SORT',
payload: { sort: 'foo', order: SORT_DESC },
payload: { field: 'foo', order: SORT_DESC },
}
);
expect(updatedState).toEqual({
Expand Down
9 changes: 6 additions & 3 deletions packages/ra-core/src/controller/list/queryReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ const oppositeOrder = direction =>
type ActionTypes =
| {
type: typeof SET_SORT;
payload: { sort: string; order?: typeof SORT_ASC | typeof SORT_DESC };
payload: {
field: string;
order?: typeof SORT_ASC | typeof SORT_DESC;
};
}
| {
type: typeof SET_PAGE;
Expand Down Expand Up @@ -57,7 +60,7 @@ export const queryReducer: Reducer<ListParams> = (
) => {
switch (action.type) {
case SET_SORT:
if (action.payload.sort === previousState.sort) {
if (action.payload.field === previousState.sort) {
return {
...previousState,
order: oppositeOrder(previousState.order),
Expand All @@ -67,7 +70,7 @@ export const queryReducer: Reducer<ListParams> = (

return {
...previousState,
sort: action.payload.sort,
sort: action.payload.field,
order: action.payload.order || SORT_ASC,
page: 1,
};
Expand Down
6 changes: 5 additions & 1 deletion packages/ra-core/src/controller/list/useList.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ describe('<useList />', () => {
const listContext = useListContext();

return (
<button onClick={() => listContext.setSort('title', 'ASC')}>
<button
onClick={() =>
listContext.setSort({ field: 'title', order: 'ASC' })
}
>
Sort by title ASC
</button>
);
Expand Down
8 changes: 4 additions & 4 deletions packages/ra-core/src/controller/list/useList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ export const useList = <RecordType extends Record = Record>(
});

// sort logic
const { sort, setSort: setSortObject } = useSortState(initialSort);
const { sort, setSort: setSortState } = useSortState(initialSort);
const setSort = useCallback(
(field: string, order = 'ASC') => {
setSortObject({ field, order });
(sort: SortPayload) => {
setSortState(sort);
setPage(1);
},
[setPage, setSortObject]
[setPage, setSortState]
);

// selection logic
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/controller/list/useListContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { Record } from '../../types';
* @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} currentSort a sort object { field, order }, e.g. { field: 'date', order: 'DESC' }
* @prop {Function} setSort a callback to change the sort, e.g. setSort('name', 'ASC')
* @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 }
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/controller/list/useListController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export interface ListControllerResult<RecordType extends Record = Record> {
) => void;
setPage: (page: number) => void;
setPerPage: (page: number) => void;
setSort: (sort: string, order?: string) => void;
setSort: (sort: SortPayload) => void;
showFilter: (filterName: string, defaultValue: any) => void;
total: number;
}
Expand Down
Loading