From d2055141bee51792c100bbf21896cb660e33268b Mon Sep 17 00:00:00 2001 From: James Date: Thu, 23 Jul 2020 17:40:16 -0400 Subject: [PATCH] performance enhancements and render reductions --- .../components/forms/RenderFields/index.js | 18 ++- .../forms/field-types/Array/index.js | 132 ++++++++++------ .../forms/field-types/Blocks/index.js | 144 +++++++++++------- 3 files changed, 195 insertions(+), 99 deletions(-) diff --git a/src/client/components/forms/RenderFields/index.js b/src/client/components/forms/RenderFields/index.js index ace2d71714..7f67c91561 100644 --- a/src/client/components/forms/RenderFields/index.js +++ b/src/client/components/forms/RenderFields/index.js @@ -1,4 +1,4 @@ -import React, { createContext, useContext } from 'react'; +import React, { createContext, useEffect, useContext, useState } from 'react'; import PropTypes from 'prop-types'; import RenderCustomComponent from '../../utilities/RenderCustomComponent'; @@ -22,12 +22,24 @@ const RenderFields = (props) => { const { customComponentsPath: customComponentsPathFromContext, operation: operationFromContext } = useRenderedFields(); - const customComponentsPath = customComponentsPathFromProps || customComponentsPathFromContext; const operation = operationFromProps || operationFromContext; + const customComponentsPath = customComponentsPathFromProps || customComponentsPathFromContext; + + const [contextValue, setContextValue] = useState({ + operation, + customComponentsPath, + }); + + useEffect(() => { + setContextValue({ + operation, + customComponentsPath, + }); + }, [operation, customComponentsPath]); if (fieldSchema) { return ( - + {fieldSchema.map((field, i) => { if (!field?.hidden && field?.admin?.disabled !== true) { if ((filter && typeof filter === 'function' && filter(field)) || !filter) { diff --git a/src/client/components/forms/field-types/Array/index.js b/src/client/components/forms/field-types/Array/index.js index 1c04c3f2b3..f49b2ccb04 100644 --- a/src/client/components/forms/field-types/Array/index.js +++ b/src/client/components/forms/field-types/Array/index.js @@ -62,7 +62,7 @@ const ArrayFieldType = (props) => { required, }); - const addRow = (rowIndex) => { + const addRow = useCallback((rowIndex) => { const data = getDataByPath(path); dispatchRows({ @@ -70,9 +70,9 @@ const ArrayFieldType = (props) => { }); setValue(value + 1); - }; + }, [dispatchRows, getDataByPath, path, setValue, value]); - const removeRow = (rowIndex) => { + const removeRow = useCallback((rowIndex) => { const data = getDataByPath(path); dispatchRows({ @@ -82,22 +82,22 @@ const ArrayFieldType = (props) => { }); setValue(value - 1); - }; + }, [dispatchRows, path, getDataByPath, setValue, value]); - const moveRow = (moveFromIndex, moveToIndex) => { + const moveRow = useCallback((moveFromIndex, moveToIndex) => { const data = getDataByPath(path); dispatchRows({ type: 'MOVE', index: moveFromIndex, moveToIndex, data, }); - }; + }, [dispatchRows, getDataByPath, path]); - const onDragEnd = (result) => { + const onDragEnd = useCallback((result) => { if (!result.destination) return; const sourceIndex = result.source.index; const destinationIndex = result.destination.index; moveRow(sourceIndex, destinationIndex); - }; + }, [moveRow]); useEffect(() => { dispatchRows({ @@ -123,6 +123,84 @@ const ArrayFieldType = (props) => { } }, [value, setValue, disableFormData, dataToInitialize]); + return ( + + ); +}; + +ArrayFieldType.defaultProps = { + label: '', + defaultValue: [], + initialData: [], + validate: array, + required: false, + maxRows: undefined, + minRows: undefined, + singularLabel: 'Row', + permissions: {}, +}; + +ArrayFieldType.propTypes = { + defaultValue: PropTypes.arrayOf( + PropTypes.shape({}), + ), + initialData: PropTypes.arrayOf( + PropTypes.shape({}), + ), + fields: PropTypes.arrayOf( + PropTypes.shape({}), + ).isRequired, + label: PropTypes.string, + singularLabel: PropTypes.string, + name: PropTypes.string.isRequired, + path: PropTypes.string.isRequired, + fieldTypes: PropTypes.shape({}).isRequired, + validate: PropTypes.func, + required: PropTypes.bool, + maxRows: PropTypes.number, + minRows: PropTypes.number, + permissions: PropTypes.shape({ + fields: PropTypes.shape({}), + }), +}; + +const RenderArray = React.memo((props) => { + const { + onDragEnd, + label, + showError, + errorMessage, + rows, + singularLabel, + addRow, + removeRow, + moveRow, + path, + customComponentsPath, + name, + fieldTypes, + fields, + permissions, + value, + } = props; + return (
@@ -179,42 +257,6 @@ const ArrayFieldType = (props) => {
); -}; - -ArrayFieldType.defaultProps = { - label: '', - defaultValue: [], - initialData: [], - validate: array, - required: false, - maxRows: undefined, - minRows: undefined, - singularLabel: 'Row', - permissions: {}, -}; - -ArrayFieldType.propTypes = { - defaultValue: PropTypes.arrayOf( - PropTypes.shape({}), - ), - initialData: PropTypes.arrayOf( - PropTypes.shape({}), - ), - fields: PropTypes.arrayOf( - PropTypes.shape({}), - ).isRequired, - label: PropTypes.string, - singularLabel: PropTypes.string, - name: PropTypes.string.isRequired, - path: PropTypes.string.isRequired, - fieldTypes: PropTypes.shape({}).isRequired, - validate: PropTypes.func, - required: PropTypes.bool, - maxRows: PropTypes.number, - minRows: PropTypes.number, - permissions: PropTypes.shape({ - fields: PropTypes.shape({}), - }), -}; +}); export default withCondition(ArrayFieldType); diff --git a/src/client/components/forms/field-types/Blocks/index.js b/src/client/components/forms/field-types/Blocks/index.js index 3f9d631f65..716ab49028 100644 --- a/src/client/components/forms/field-types/Blocks/index.js +++ b/src/client/components/forms/field-types/Blocks/index.js @@ -15,7 +15,7 @@ import Error from '../../Error'; import useFieldType from '../../useFieldType'; import Popup from '../../../elements/Popup'; import BlockSelector from './BlockSelector'; -import { blocks } from '../../../../../fields/validations'; +import { blocks as blocksValidator } from '../../../../../fields/validations'; import './index.scss'; @@ -71,7 +71,7 @@ const Blocks = (props) => { const { customComponentsPath } = useRenderedFields(); const { getDataByPath } = useForm(); - const addRow = (index, blockType) => { + const addRow = useCallback((index, blockType) => { const data = getDataByPath(path); dispatchRows({ @@ -79,9 +79,9 @@ const Blocks = (props) => { }); setValue(value + 1); - }; + }, [getDataByPath, path, setValue, value]); - const removeRow = (index) => { + const removeRow = useCallback((index) => { const data = getDataByPath(path); dispatchRows({ @@ -91,28 +91,28 @@ const Blocks = (props) => { }); setValue(value - 1); - }; + }, [getDataByPath, path, setValue, value]); - const moveRow = (moveFromIndex, moveToIndex) => { + const moveRow = useCallback((moveFromIndex, moveToIndex) => { const data = getDataByPath(path); dispatchRows({ type: 'MOVE', index: moveFromIndex, moveToIndex, data, }); - }; + }, [getDataByPath, path]); - const toggleCollapse = (index) => { + const toggleCollapse = useCallback((index) => { dispatchRows({ type: 'TOGGLE_COLLAPSE', index, rows, }); - }; + }, [rows]); - const onDragEnd = (result) => { + const onDragEnd = useCallback((result) => { if (!result.destination) return; const sourceIndex = result.source.index; const destinationIndex = result.destination.index; moveRow(sourceIndex, destinationIndex); - }; + }, [moveRow]); useEffect(() => { dispatchRows({ @@ -138,6 +138,87 @@ const Blocks = (props) => { } }, [value, setValue, disableFormData, dataToInitialize]); + return ( + + ); +}; + +Blocks.defaultProps = { + label: '', + defaultValue: [], + initialData: [], + singularLabel: 'Block', + validate: blocksValidator, + required: false, + maxRows: undefined, + minRows: undefined, + permissions: {}, +}; + +Blocks.propTypes = { + blocks: PropTypes.arrayOf( + PropTypes.shape({}), + ).isRequired, + defaultValue: PropTypes.arrayOf( + PropTypes.shape({}), + ), + initialData: PropTypes.arrayOf( + PropTypes.shape({}), + ), + label: PropTypes.string, + singularLabel: PropTypes.string, + name: PropTypes.string.isRequired, + path: PropTypes.string.isRequired, + fieldTypes: PropTypes.shape({}).isRequired, + validate: PropTypes.func, + required: PropTypes.bool, + maxRows: PropTypes.number, + minRows: PropTypes.number, + permissions: PropTypes.shape({ + fields: PropTypes.shape({}), + }), +}; + +const RenderBlock = React.memo((props) => { + const { + onDragEnd, + label, + showError, + errorMessage, + rows, + singularLabel, + addRow, + removeRow, + moveRow, + path, + customComponentsPath, + name, + fieldTypes, + permissions, + value, + toggleCollapse, + dataToInitialize, + blocks, + } = props; return ( @@ -235,45 +316,6 @@ const Blocks = (props) => { ); -}; - -Blocks.defaultProps = { - label: '', - defaultValue: [], - initialData: [], - singularLabel: 'Block', - validate: blocks, - required: false, - maxRows: undefined, - minRows: undefined, - permissions: {}, -}; - -Blocks.propTypes = { - blocks: PropTypes.arrayOf( - PropTypes.shape({}), - ).isRequired, - defaultValue: PropTypes.arrayOf( - PropTypes.shape({}), - ), - initialData: PropTypes.arrayOf( - PropTypes.shape({}), - ), - blocks: PropTypes.arrayOf( - PropTypes.shape({}), - ).isRequired, - label: PropTypes.string, - singularLabel: PropTypes.string, - name: PropTypes.string.isRequired, - path: PropTypes.string.isRequired, - fieldTypes: PropTypes.shape({}).isRequired, - validate: PropTypes.func, - required: PropTypes.bool, - maxRows: PropTypes.number, - minRows: PropTypes.number, - permissions: PropTypes.shape({ - fields: PropTypes.shape({}), - }), -}; +}); export default withCondition(Blocks);