Skip to content

Commit

Permalink
Improve React Vanilla bindings
Browse files Browse the repository at this point in the history
The React Vanilla renderers add additional bindings for style
customizations. The calculated props are now properly memoized
so that the standard React memoization can take effect.
  • Loading branch information
sdirix committed Oct 14, 2021
1 parent 8eeae86 commit 46e16e7
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 26 deletions.
10 changes: 8 additions & 2 deletions packages/vanilla/src/layouts/GroupLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ import { withVanillaControlProps } from '../util';
*/
export const groupTester: RankedTester = rankWith(1, uiTypeIs('Group'));

export const GroupLayoutRenderer: FunctionComponent<RendererProps & VanillaRendererProps> = (
export const GroupLayoutRenderer = (props: RendererProps & VanillaRendererProps) => {
const {data, ...otherProps} = props;
// We don't hand over data to the layout renderer to avoid rerendering it with every data change
return <GroupLayoutRendererComponent {...otherProps}/>;
}

const GroupLayoutRendererComponent: FunctionComponent<RendererProps & VanillaRendererProps> = React.memo((
{
schema,
uischema,
Expand Down Expand Up @@ -67,6 +73,6 @@ export const GroupLayoutRenderer: FunctionComponent<RendererProps & VanillaRende
{renderChildren(group, schema, childClassNames, path)}
</fieldset>
);
};
});

export default withVanillaControlProps(withJsonFormsLayoutProps(GroupLayoutRenderer));
12 changes: 9 additions & 3 deletions packages/vanilla/src/layouts/HorizontalLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ import { VanillaRendererProps } from '../index';
*/
export const horizontalLayoutTester: RankedTester = rankWith(1, uiTypeIs('HorizontalLayout'));

const HorizontalLayoutRenderer: FunctionComponent<RendererProps & VanillaRendererProps> = (
export const HorizontalLayoutRenderer = (props: RendererProps & VanillaRendererProps) => {
const {data, ...otherProps} = props;
// We don't hand over data to the layout renderer to avoid rerendering it with every data change
return <HorizontalLayoutRendererComponent {...otherProps}/>;
}

const HorizontalLayoutRendererComponent: FunctionComponent<RendererProps & VanillaRendererProps> = React.memo((
{
schema,
uischema,
Expand Down Expand Up @@ -75,6 +81,6 @@ const HorizontalLayoutRenderer: FunctionComponent<RendererProps & VanillaRendere
{renderChildren(horizontalLayout, schema, childClassNames, path)}
</JsonFormsLayout>
);
};
});

export default withVanillaControlProps(withJsonFormsLayoutProps(HorizontalLayoutRenderer));
export default withVanillaControlProps(withJsonFormsLayoutProps(HorizontalLayoutRenderer, false));
2 changes: 0 additions & 2 deletions packages/vanilla/src/layouts/JsonFormsLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ import React from 'react';
import { RendererProps } from '@jsonforms/core';
import { VanillaRendererProps, WithChildren } from '../index';

// tslint:disable:variable-name
export const JsonFormsLayout =
({ className, children, visible }: RendererProps & VanillaRendererProps & WithChildren) => {
// tslint:enable:variable-name

return (
<div
Expand Down
12 changes: 9 additions & 3 deletions packages/vanilla/src/layouts/VerticalLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ import { VanillaRendererProps } from '../index';
*/
export const verticalLayoutTester: RankedTester = rankWith(1, uiTypeIs('VerticalLayout'));

export const VerticalLayoutRenderer: FunctionComponent<RendererProps & VanillaRendererProps> = (
export const VerticalLayoutRenderer = (props: RendererProps & VanillaRendererProps) => {
const {data, ...otherProps} = props;
// We don't hand over data to the layout renderer to avoid rerendering it with every data change
return <VerticalLayoutRendererComponent {...otherProps}/>;
}

const VerticalLayoutRendererComponent: FunctionComponent<RendererProps & VanillaRendererProps> = React.memo((
{
schema,
uischema,
Expand Down Expand Up @@ -74,6 +80,6 @@ export const VerticalLayoutRenderer: FunctionComponent<RendererProps & VanillaRe
{renderChildren(verticalLayout, schema, childClassNames, path)}
</JsonFormsLayout>
);
};
});

export default withVanillaControlProps(withJsonFormsLayoutProps(VerticalLayoutRenderer));
export default withVanillaControlProps(withJsonFormsLayoutProps(VerticalLayoutRenderer, false));
41 changes: 25 additions & 16 deletions packages/vanilla/src/util/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import {
import { useJsonForms } from '@jsonforms/react';
import { getStyle, getStyleAsClassName } from '../reducers';
import { VanillaRendererProps } from '../index';
import { ComponentType } from 'react';
import { ComponentType, useMemo } from 'react';
import { findStyle, findStyleAsClassName } from '../reducers/styling';
import { useStyles } from '../styles';

Expand Down Expand Up @@ -96,7 +96,7 @@ export const withVanillaControlProps = (Component: ComponentType<any>) => (props
const controlElement = props.uischema as ControlElement;
const config = ctx.config;
const trim = config && config.trim;
const styles = findStyle(contextStyles)('control');
const styles = useMemo(() => findStyle(contextStyles)('control'), [contextStyles]);
let classNames: string[] = !isEmpty(controlElement.scope)
? styles.concat([`${convertToValidClassName(controlElement.scope)}`])
: [''];
Expand All @@ -105,24 +105,33 @@ export const withVanillaControlProps = (Component: ComponentType<any>) => (props
classNames = classNames.concat(findStyle(contextStyles)('control.trim'));
}
const isValid = isEmpty(props.errors);
const labelClass = findStyleAsClassName(contextStyles)('control.label');
const descriptionClassName = findStyleAsClassName(contextStyles)('input.description');
const validationClassName = findStyleAsClassName(contextStyles)('control.validation');
const validationErrorClassName = findStyleAsClassName(contextStyles)('control.validation.error');
const labelClass = useMemo(() => findStyleAsClassName(contextStyles)('control.label'), [contextStyles]);
const descriptionClassName = useMemo(() => findStyleAsClassName(contextStyles)('input.description'), [contextStyles]);
const validationClassName = useMemo(() => findStyleAsClassName(contextStyles)('control.validation'), [contextStyles]);
const validationErrorClassName = useMemo(() => findStyleAsClassName(contextStyles)('control.validation.error'), [contextStyles]);
const inputClassName = ['validate'].concat(isValid ? 'valid' : 'invalid');

const getStyleAsClassName = useMemo(() => findStyleAsClassName(contextStyles), [contextStyles]);
const getStyle = useMemo(() => findStyle(contextStyles), [contextStyles]);

const wrapper = classNames.join(' ');
const input = inputClassName.join(' ');

const classNamesProp = useMemo(() => ({
wrapper,
input,
label: labelClass,
description: descriptionClassName,
validation: validationClassName,
validationError: validationErrorClassName
}), [wrapper, input, labelClass, descriptionClassName, validationClassName, validationErrorClassName]);

return (
<Component
{...props}
getStyleAsClassName={findStyleAsClassName(contextStyles)}
getStyle={findStyle(contextStyles)}
classNames={{
wrapper: classNames.join(' '),
input: inputClassName.join(' '),
label: labelClass,
description: descriptionClassName,
validation: validationClassName,
validationError: validationErrorClassName
}}
getStyleAsClassName={getStyleAsClassName}
getStyle={getStyle}
classNames={classNamesProp}
/>
);
}
Expand Down

0 comments on commit 46e16e7

Please sign in to comment.