From bbe62f922024792f6f8acfc0f809d4ee6e3a0ef2 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Wed, 21 Aug 2019 14:01:04 +0200 Subject: [PATCH] use useGetMany in useReferencearrayfieldcontroller instead of crudGetManyAccumulate Closes #3552 --- .../field/useReferenceArrayFieldController.ts | 57 ++++++++----------- .../ra-core/src/dataProvider/useGetMany.ts | 12 ++++ .../src/field/ReferenceArrayField.js | 13 +++-- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/packages/ra-core/src/controller/field/useReferenceArrayFieldController.ts b/packages/ra-core/src/controller/field/useReferenceArrayFieldController.ts index 1817942b0b..2432b3e1bc 100644 --- a/packages/ra-core/src/controller/field/useReferenceArrayFieldController.ts +++ b/packages/ra-core/src/controller/field/useReferenceArrayFieldController.ts @@ -1,23 +1,25 @@ -import { useEffect } from 'react'; -import { useDispatch, useSelector, shallowEqual } from 'react-redux'; +import { useMemo } from 'react'; import get from 'lodash/get'; -import { crudGetManyAccumulate } from '../../actions'; -import { getReferencesByIds } from '../../reducer/admin/references/oneToMany'; -import { ReduxState, Record, RecordMap, Identifier } from '../../types'; +import { Record, RecordMap, Identifier } from '../../types'; +import { useGetMany } from '../../dataProvider'; /** * @typedef ReferenceArrayProps * @type {Object} - * @property {boolean} loaded: boolean indicating if the reference has already beeen loaded - * @property {Array} ids: the list of ids. - * @property {Object} data: Object holding the reference data by their ids + * @property {Array} ids the list of ids. + * @property {Object} data Object holding the reference data by their ids + * @property {Object} error the error returned by the dataProvider + * @property {boolean} loading is the reference currently loading + * @property {boolean} loaded has the reference already been loaded * @property {string} referenceBasePath basePath of the reference */ interface ReferenceArrayProps { - loaded: boolean; ids: Identifier[]; data: RecordMap; + error?: any; + loading: boolean; + loaded: boolean; referenceBasePath: string; } @@ -35,7 +37,7 @@ interface Option { * * @example * - * const { loaded, data, ids, referenceBasePath, currentSort } = useReferenceArrayFieldController({ + * const { ids, data, error, loaded, loading, referenceBasePath } = useReferenceArrayFieldController({ * basePath: 'resource'; * record: { referenceIds: ['id1', 'id2']}; * reference: 'reference'; @@ -61,34 +63,25 @@ const useReferenceArrayFieldController = ({ record, source, }: Option): ReferenceArrayProps => { - const dispatch = useDispatch(); - const { data, ids } = useSelector( - getReferenceArray({ record, source, reference }), - shallowEqual - ); - useEffect(() => { - dispatch(crudGetManyAccumulate(reference, ids)); - }, [reference, ids, record.id]); // eslint-disable-line react-hooks/exhaustive-deps - + const ids = get(record, source) || []; + const { data, error, loading, loaded } = useGetMany(reference, ids); const referenceBasePath = basePath.replace(resource, reference); // FIXME obviously very weak - return { - // eslint-disable-next-line eqeqeq - loaded: data != undefined, ids, - data, + data: useMemo(() => indexById(data), [data]), + error, + loaded, + loading, referenceBasePath, }; }; -const getReferenceArray = ({ record, source, reference }) => ( - state: ReduxState -) => { - const ids = get(record, source) || []; - return { - data: getReferencesByIds(state, reference, ids), - ids, - }; -}; +const indexById = (records: Record[]) => + records + .filter(r => typeof r !== 'undefined') + .reduce((prev, current) => { + prev[current.id] = current; + return prev; + }, {}); export default useReferenceArrayFieldController; diff --git a/packages/ra-core/src/dataProvider/useGetMany.ts b/packages/ra-core/src/dataProvider/useGetMany.ts index a3c393c3ec..973fc89d86 100644 --- a/packages/ra-core/src/dataProvider/useGetMany.ts +++ b/packages/ra-core/src/dataProvider/useGetMany.ts @@ -155,6 +155,16 @@ const callQueries = debounce(() => { .filter(v => v != null); // remove null values if (accumulatedIds.length === 0) { // no need to call the data provider if all the ids are null + queries.forEach(({ ids, setState, onSuccess }) => { + setState({ + data: emptyArray, + loading: false, + loaded: true, + }); + if (onSuccess) { + onSuccess({ data: emptyArray }); + } + }); return; } dataProvider( @@ -188,4 +198,6 @@ const callQueries = debounce(() => { }); }); +const emptyArray = []; + export default useGetMany; diff --git a/packages/ra-ui-materialui/src/field/ReferenceArrayField.js b/packages/ra-ui-materialui/src/field/ReferenceArrayField.js index df38144f4e..9e6698d645 100644 --- a/packages/ra-ui-materialui/src/field/ReferenceArrayField.js +++ b/packages/ra-ui-materialui/src/field/ReferenceArrayField.js @@ -1,4 +1,4 @@ -import React, { Children, cloneElement } from 'react'; +import React, { Children, cloneElement, memo } from 'react'; import PropTypes from 'prop-types'; import LinearProgress from '@material-ui/core/LinearProgress'; import { makeStyles } from '@material-ui/core/styles'; @@ -45,11 +45,12 @@ export const ReferenceArrayField = ({ children, ...props }) => { } return ( - + > + {children} + ); }; @@ -87,7 +88,7 @@ export const ReferenceArrayFieldView = ({ referenceBasePath, }) => { const classes = useStyles({ classes: classesOverride }); - if (loaded === false) { + if (!loaded) { return ; } @@ -113,4 +114,6 @@ ReferenceArrayFieldView.propTypes = { referenceBasePath: PropTypes.string, }; +const PureReferenceArrayFieldView = memo(ReferenceArrayFieldView); + export default ReferenceArrayField;