diff --git a/packages/ra-ui-materialui/src/field/ArrayField.tsx b/packages/ra-ui-materialui/src/field/ArrayField.tsx index b0c7f1bf5c0..0a8819e81a3 100644 --- a/packages/ra-ui-materialui/src/field/ArrayField.tsx +++ b/packages/ra-ui-materialui/src/field/ArrayField.tsx @@ -1,9 +1,20 @@ -import { Component, cloneElement, Children } from 'react'; +import { + FunctionComponent, + cloneElement, + Children, + useEffect, + useState, + memo, +} from 'react'; import get from 'lodash/get'; -import pure from 'recompose/pure'; import { Identifier } from 'ra-core'; import { FieldProps, InjectedFieldProps, fieldPropTypes } from './types'; +import PropTypes from 'prop-types'; + +interface ArrayFieldProps { + fieldKey?: string; +} interface State { data: object; @@ -15,6 +26,28 @@ const initialState = { ids: [], }; +const getDataAndIds = (record: object, source: string, fieldKey: string) => { + const list = get(record, source); + if (!list) { + return initialState; + } + return fieldKey + ? { + data: list.reduce((prev, item) => { + prev[item[fieldKey]] = item; + return prev; + }, {}), + ids: list.map(item => item[fieldKey]), + } + : { + data: list.reduce((prev, item) => { + prev[JSON.stringify(item)] = item; + return prev; + }, {}), + ids: list.map(JSON.stringify), + }; +}; + /** * Display a collection * @@ -88,86 +121,45 @@ const initialState = { * ) * TagsField.defaultProps = { addLabel: true }; */ -export class ArrayField extends Component< - FieldProps & InjectedFieldProps, - State -> { - constructor(props: FieldProps & InjectedFieldProps) { - super(props); - this.state = props.record - ? this.getDataAndIds(props.record, props.source, props.fieldKey) - : initialState; - } +export const ArrayField: FunctionComponent< + ArrayFieldProps & FieldProps & InjectedFieldProps +> = ({ + addLabel, + basePath, + children, + record, + sortable, + source, + fieldKey, + ...rest +}) => { + const [ids, setIds] = useState(); + const [data, setData] = useState(); - componentWillReceiveProps( - nextProps: FieldProps & InjectedFieldProps, - prevProps: FieldProps & InjectedFieldProps - ) { - if (nextProps.record !== prevProps.record) { - this.setState( - this.getDataAndIds( - nextProps.record, - nextProps.source, - nextProps.fieldKey - ) - ); - } - } + useEffect(() => { + const { ids, data } = getDataAndIds(record, source, fieldKey); + setIds(ids); + setData(data); + }, [record, source, fieldKey]); - getDataAndIds(record: object, source: string, fieldKey: string) { - const list = get(record, source); - if (!list) { - return initialState; - } - return fieldKey - ? { - data: list.reduce((prev, item) => { - prev[item[fieldKey]] = item; - return prev; - }, {}), - ids: list.map(item => item[fieldKey]), - } - : { - data: list.reduce((prev, item) => { - prev[JSON.stringify(item)] = item; - return prev; - }, {}), - ids: list.map(JSON.stringify), - }; - } - - render() { - const { - addLabel, - basePath, - children, - record, - sortable, - source, - fieldKey, - ...rest - } = this.props; - const { ids, data } = this.state; - - // @ts-ignore - return cloneElement(Children.only(children), { - ids, - data, - loading: false, - basePath, - currentSort: {}, - ...rest, - }); - } -} - -const EnhancedArrayField = pure(ArrayField); + // @ts-ignore + return cloneElement(Children.only(children), { + ids, + data, + loading: false, + basePath, + currentSort: {}, + ...rest, + }); +}; -EnhancedArrayField.defaultProps = { +ArrayField.defaultProps = { addLabel: true, }; -EnhancedArrayField.propTypes = fieldPropTypes; -EnhancedArrayField.displayName = 'EnhancedArrayField'; +ArrayField.propTypes = { + ...fieldPropTypes, + fieldKey: PropTypes.string, +}; -export default EnhancedArrayField; +export default memo(ArrayField); diff --git a/packages/ra-ui-materialui/src/field/types.ts b/packages/ra-ui-materialui/src/field/types.ts index 59025e6bb37..a91c40538e7 100644 --- a/packages/ra-ui-materialui/src/field/types.ts +++ b/packages/ra-ui-materialui/src/field/types.ts @@ -13,7 +13,6 @@ export interface FieldProps { headerClassName?: string; textAlign?: TextAlign; emptyText?: string; - fieldKey?: string; } // Props injected by react-admin @@ -33,5 +32,4 @@ export const fieldPropTypes = { headerClassName: PropTypes.string, textAlign: PropTypes.oneOf(['right', 'left']), emptyText: PropTypes.string, - fieldKey: PropTypes.string, }; diff --git a/packages/ra-ui-materialui/tsconfig.json b/packages/ra-ui-materialui/tsconfig.json index 8be9b276492..966443ed67b 100644 --- a/packages/ra-ui-materialui/tsconfig.json +++ b/packages/ra-ui-materialui/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src" - }, - "exclude": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js"], - "include": ["src"] + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src" + }, + "exclude": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js"], + "include": ["src"] }