diff --git a/packages/ra-core/src/controller/details/useCreateContext.tsx b/packages/ra-core/src/controller/details/useCreateContext.tsx index e8299188d8f..655afcfd065 100644 --- a/packages/ra-core/src/controller/details/useCreateContext.tsx +++ b/packages/ra-core/src/controller/details/useCreateContext.tsx @@ -1,5 +1,5 @@ import { useContext, useMemo } from 'react'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; import { Record } from '../../types'; import { CreateContext } from './CreateContext'; @@ -35,10 +35,10 @@ export const useCreateContext = < // Props take precedence over the context return useMemo( () => - merge( + defaults( {}, - context, - props != null ? extractCreateContextProps(props) : {} + props != null ? extractCreateContextProps(props) : {}, + context ), [context, props] ); diff --git a/packages/ra-core/src/controller/details/useEditContext.tsx b/packages/ra-core/src/controller/details/useEditContext.tsx index b811e7927b3..ad55e753469 100644 --- a/packages/ra-core/src/controller/details/useEditContext.tsx +++ b/packages/ra-core/src/controller/details/useEditContext.tsx @@ -1,5 +1,5 @@ import { useContext, useMemo } from 'react'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; import { Record } from '../../types'; import { EditContext } from './EditContext'; @@ -32,10 +32,10 @@ export const useEditContext = <RecordType extends Record = Record>( // Props take precedence over the context return useMemo( () => - merge( + defaults( {}, - context, - props != null ? extractEditContextProps(props) : {} + props != null ? extractEditContextProps(props) : {}, + context ), [context, props] ); diff --git a/packages/ra-core/src/controller/details/useShowContext.tsx b/packages/ra-core/src/controller/details/useShowContext.tsx index a74e3e46365..ef853cbeef7 100644 --- a/packages/ra-core/src/controller/details/useShowContext.tsx +++ b/packages/ra-core/src/controller/details/useShowContext.tsx @@ -1,5 +1,5 @@ import { useContext, useMemo } from 'react'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; import { Record } from '../../types'; import { ShowContext } from './ShowContext'; @@ -32,10 +32,10 @@ export const useShowContext = <RecordType extends Record = Record>( // Props take precedence over the context return useMemo( () => - merge( + defaults( {}, - context, - props != null ? extractShowContextProps(props) : {} + props != null ? extractShowContextProps(props) : {}, + context ), [context, props] ); diff --git a/packages/ra-core/src/controller/input/useReferenceArrayInputContext.ts b/packages/ra-core/src/controller/input/useReferenceArrayInputContext.ts index d5f96306b20..4cffb49111b 100644 --- a/packages/ra-core/src/controller/input/useReferenceArrayInputContext.ts +++ b/packages/ra-core/src/controller/input/useReferenceArrayInputContext.ts @@ -1,5 +1,5 @@ import { useContext, useMemo } from 'react'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; import { ReferenceArrayInputContext, ReferenceArrayInputContextValue, @@ -17,12 +17,12 @@ export const useReferenceArrayInputContext = < // Props take precedence over the context return useMemo( () => - merge( + defaults( {}, - context, props != null ? extractReferenceArrayInputContextProps(props) - : {} + : {}, + context ), [context, props] ); diff --git a/packages/ra-core/src/controller/useListContext.ts b/packages/ra-core/src/controller/useListContext.ts index 48609fb749b..67d47ddc215 100644 --- a/packages/ra-core/src/controller/useListContext.ts +++ b/packages/ra-core/src/controller/useListContext.ts @@ -1,5 +1,5 @@ import { useContext, useMemo } from 'react'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; import ListContext from './ListContext'; import { ListControllerProps } from './useListController'; @@ -101,10 +101,10 @@ const useListContext = <RecordType extends Record = Record>( // @ts-ignore return useMemo( () => - merge( + defaults( {}, - context, - props != null ? extractListContextProps(props) : {} + props != null ? extractListContextProps(props) : {}, + context ), [context, props] ); diff --git a/packages/ra-core/src/controller/useRecordSelection.ts b/packages/ra-core/src/controller/useRecordSelection.ts index bdb12d3ed29..57dfa2aeb30 100644 --- a/packages/ra-core/src/controller/useRecordSelection.ts +++ b/packages/ra-core/src/controller/useRecordSelection.ts @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { useMemo } from 'react'; import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import { setListSelectedIds, toggleListItem } from '../actions/listActions'; import { Identifier, ReduxState } from '../types'; @@ -30,23 +30,20 @@ const useRecordSelection = ( : defaultRecords, shallowEqual ); - const selectionModifiers = { - select: useCallback( - (newIds: Identifier[]) => { + const selectionModifiers = useMemo( + () => ({ + select: (newIds: Identifier[]) => { dispatch(setListSelectedIds(resource, newIds)); }, - [resource] // eslint-disable-line react-hooks/exhaustive-deps - ), - toggle: useCallback( - (id: Identifier) => { + toggle: (id: Identifier) => { dispatch(toggleListItem(resource, id)); }, - [resource] // eslint-disable-line react-hooks/exhaustive-deps - ), - clearSelection: useCallback(() => { - dispatch(setListSelectedIds(resource, [])); - }, [resource]), // eslint-disable-line react-hooks/exhaustive-deps - }; + clearSelection: () => { + dispatch(setListSelectedIds(resource, [])); + }, + }), + [dispatch, resource] + ); return [selectedIds, selectionModifiers]; }; diff --git a/packages/ra-core/src/core/useResourceDefinition.ts b/packages/ra-core/src/core/useResourceDefinition.ts index c204ae1c869..34535073bb4 100644 --- a/packages/ra-core/src/core/useResourceDefinition.ts +++ b/packages/ra-core/src/core/useResourceDefinition.ts @@ -1,5 +1,5 @@ import { useSelector } from 'react-redux'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; import { getResources } from '../reducer'; import { ResourceDefinition } from '../types'; import { useResourceContext } from './useResourceContext'; @@ -17,12 +17,16 @@ export const useResourceDefinition = ( const definition = useMemo(() => { const definitionFromRedux = resources.find(r => r?.name === resource); - return merge({}, definitionFromRedux, { - hasCreate, - hasEdit, - hasList, - hasShow, - }); + return defaults( + {}, + { + hasCreate, + hasEdit, + hasList, + hasShow, + }, + definitionFromRedux + ); }, [resource, resources, hasCreate, hasEdit, hasList, hasShow]); return definition; diff --git a/packages/ra-core/src/dataProvider/useDataProvider.spec.js b/packages/ra-core/src/dataProvider/useDataProvider.spec.js index b4f4de7f233..0ae8a806d0d 100644 --- a/packages/ra-core/src/dataProvider/useDataProvider.spec.js +++ b/packages/ra-core/src/dataProvider/useDataProvider.spec.js @@ -422,7 +422,7 @@ describe('useDataProvider', () => { expect(update).toBeCalledTimes(1); // make sure the side effect hasn't been applied yet expect(queryByText('(updated)')).toBeNull(); - await act(() => { + await act(async () => { resolveUpdate(); }); // side effects should be applied now @@ -473,7 +473,7 @@ describe('useDataProvider', () => { // side effects should be applied now expect(queryByText('(updated)')).not.toBeNull(); expect(update).toBeCalledTimes(1); - await act(() => { + act(() => { resolveUpdate(); }); }); @@ -521,7 +521,7 @@ describe('useDataProvider', () => { expect(queryByText('(updated)')).not.toBeNull(); // update shouldn't be called at all expect(update).toBeCalledTimes(0); - await act(() => { + act(() => { undoableEventEmitter.emit('end', {}); }); expect(update).toBeCalledTimes(1); diff --git a/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx b/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx index 35b6a9c2009..15c994adc9a 100644 --- a/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx +++ b/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx @@ -500,7 +500,7 @@ describe('<SimpleFormIterator />', () => { }); it('should call the onClick method when the custom add button is clicked', async () => { - const onClick = jest.fn(); + const onClick = jest.fn().mockImplementation(e => e.preventDefault()); const { getByText } = renderWithRedux( <ThemeProvider theme={theme}> <SaveContextProvider value={saveContextValue}> @@ -527,7 +527,7 @@ describe('<SimpleFormIterator />', () => { }); it('should call the onClick method when the custom remove button is clicked', async () => { - const onClick = jest.fn(); + const onClick = jest.fn().mockImplementation(e => e.preventDefault()); const { getByText } = renderWithRedux( <ThemeProvider theme={theme}> <SaveContextProvider value={saveContextValue}> diff --git a/packages/ra-ui-materialui/src/list/datagrid/useDatagridContext.ts b/packages/ra-ui-materialui/src/list/datagrid/useDatagridContext.ts index 726843d94c7..efda342d335 100644 --- a/packages/ra-ui-materialui/src/list/datagrid/useDatagridContext.ts +++ b/packages/ra-ui-materialui/src/list/datagrid/useDatagridContext.ts @@ -1,7 +1,7 @@ import { useContext, useMemo } from 'react'; import { DatagridProps } from './Datagrid'; import DatagridContext, { DatagridContextValue } from './DatagridContext'; -import merge from 'lodash/merge'; +import defaults from 'lodash/defaults'; export const useDatagridContext = ( props?: DatagridProps @@ -10,10 +10,10 @@ export const useDatagridContext = ( return useMemo( () => - merge( + defaults( {}, - context, - props != null ? { isRowExpandable: props.isRowExpandable } : {} + props != null ? { isRowExpandable: props.isRowExpandable } : {}, + context ), [context, props] );