Skip to content

Commit 37065bd

Browse files
edgarmuellereneufeld
authored andcommitted
[react] Improve performance related to context
Split usage of context and mapping of properties by using additional HOCs which allows usage of React.memo as only the properties can be checked via an areEqual function. Only perform call to hasRefs within ResolvedJsonFormsDispatchRenderer if schemas are not equal. Provide CombinatorProps intersection type.
1 parent 0bef851 commit 37065bd

File tree

5 files changed

+305
-200
lines changed

5 files changed

+305
-200
lines changed

packages/core/src/util/renderer.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ import {
4949
formatErrorMessage,
5050
isEnabled,
5151
isVisible,
52-
Resolve,
53-
resolveSubSchemas,
52+
moveDown,
5453
moveUp,
55-
moveDown
54+
Resolve,
55+
resolveSubSchemas
5656
} from '../util';
5757
import has from 'lodash/has';
5858
import { update } from '../actions';
@@ -293,6 +293,8 @@ export interface StatePropsOfControl extends StatePropsOfScopedRenderer {
293293
* Whether the rendered data is required.
294294
*/
295295
required?: boolean;
296+
297+
// TODO: renderers?
296298
}
297299

298300
/**
@@ -839,6 +841,8 @@ export const mapStateToArrayLayoutProps = (
839841
};
840842
};
841843

844+
export type CombinatorProps = StatePropsOfCombinator & DispatchPropsOfControl;
845+
842846
/**
843847
* Props of an array control.
844848
*/

packages/material/src/complex/MaterialOneOfRenderer.tsx

Lines changed: 84 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@
2525
import React, { useCallback, useState } from 'react';
2626

2727
import {
28+
CombinatorProps,
2829
createCombinatorRenderInfos,
2930
createDefaultValue,
3031
isOneOfControl,
3132
JsonSchema,
3233
OwnPropsOfControl,
3334
RankedTester,
3435
rankWith,
35-
resolveSubSchemas,
36-
DispatchPropsOfControl,
37-
StatePropsOfCombinator
36+
resolveSubSchemas
3837
} from '@jsonforms/core';
3938
import {
4039
Button,
@@ -47,112 +46,96 @@ import {
4746
Tab,
4847
Tabs
4948
} from '@material-ui/core';
50-
import { JsonFormsDispatch, withJsonFormsOneOfProps } from '@jsonforms/react';
49+
import {
50+
JsonFormsDispatch,
51+
withJsonFormsOneOfProps
52+
} from '@jsonforms/react';
5153
import CombinatorProperties from './CombinatorProperties';
5254

5355
export interface OwnOneOfProps extends OwnPropsOfControl {
5456
indexOfFittingSchema?: number;
5557
}
58+
5659
const oneOf = 'oneOf';
57-
const MaterialOneOfRenderer = ({
58-
handleChange,
59-
schema,
60-
path,
61-
renderers,
62-
rootSchema,
63-
id,
64-
visible,
65-
indexOfFittingSchema,
66-
uischema,
67-
uischemas
68-
}: StatePropsOfCombinator & DispatchPropsOfControl) => {
69-
const [open, setOpen] = useState(false);
70-
const [selectedIndex, setSelectedIndex] = useState(indexOfFittingSchema || 0);
71-
const [newSelectedIndex, setNewSelectedIndex] = useState(0);
72-
const handleClose = useCallback(() => setOpen(false), [setOpen]);
73-
const cancel = useCallback(() => {
74-
setOpen(false);
75-
}, [setOpen]);
76-
const handleTabChange = useCallback(
77-
(_event: any, newOneOfIndex: number) => {
60+
const MaterialOneOfRenderer =
61+
({ handleChange, schema, path, renderers, rootSchema, id, visible, indexOfFittingSchema, uischema, uischemas }: CombinatorProps) => {
62+
const [open, setOpen] = useState(false);
63+
const [selectedIndex, setSelectedIndex] = useState(indexOfFittingSchema || 0);
64+
const [newSelectedIndex, setNewSelectedIndex] = useState(0);
65+
const handleClose = useCallback(() => setOpen(false), [setOpen]);
66+
const cancel = useCallback(() => {
67+
setOpen(false);
68+
}, [setOpen]);
69+
const handleTabChange = useCallback((_event: any, newOneOfIndex: number) => {
7870
setOpen(true);
7971
setNewSelectedIndex(newOneOfIndex);
80-
},
81-
[setOpen, setSelectedIndex]
82-
);
83-
//const { handleChange } = ctxDispatchToControlProps(dispatch);
84-
const _schema = resolveSubSchemas(schema, rootSchema, oneOf);
85-
const oneOfRenderInfos = createCombinatorRenderInfos(
86-
(_schema as JsonSchema).oneOf,
87-
rootSchema,
88-
oneOf,
89-
uischema,
90-
path,
91-
uischemas
92-
);
93-
const confirm = useCallback(() => {
94-
handleChange(path, createDefaultValue(schema.oneOf[newSelectedIndex]));
95-
setOpen(false);
96-
setSelectedIndex(newSelectedIndex);
97-
}, [handleChange, createDefaultValue, newSelectedIndex]);
72+
}, [setOpen, setSelectedIndex]);
73+
const _schema = resolveSubSchemas(schema, rootSchema, oneOf);
74+
const oneOfRenderInfos = createCombinatorRenderInfos(
75+
(_schema as JsonSchema).oneOf,
76+
rootSchema,
77+
oneOf,
78+
uischema,
79+
path,
80+
uischemas
81+
);
82+
const confirm = useCallback(() => {
83+
handleChange(
84+
path,
85+
createDefaultValue(schema.oneOf[newSelectedIndex])
86+
);
87+
setOpen(false);
88+
setSelectedIndex(newSelectedIndex);
89+
}, [handleChange, createDefaultValue, newSelectedIndex]);
9890

99-
return (
100-
<Hidden xsUp={!visible}>
101-
<CombinatorProperties
102-
schema={_schema}
103-
combinatorKeyword={'oneOf'}
104-
path={path}
105-
/>
106-
<Tabs value={selectedIndex} onChange={handleTabChange}>
107-
{oneOfRenderInfos.map(oneOfRenderInfo => (
108-
<Tab key={oneOfRenderInfo.label} label={oneOfRenderInfo.label} />
109-
))}
110-
</Tabs>
111-
{oneOfRenderInfos.map(
112-
(oneOfRenderInfo, oneOfIndex) =>
113-
selectedIndex === oneOfIndex && (
114-
<JsonFormsDispatch
115-
key={oneOfIndex}
116-
schema={oneOfRenderInfo.schema}
117-
uischema={oneOfRenderInfo.uischema}
118-
path={path}
119-
renderers={renderers}
120-
/>
121-
)
122-
)}
123-
<Dialog
124-
open={open}
125-
onClose={handleClose}
126-
aria-labelledby='alert-dialog-title'
127-
aria-describedby='alert-dialog-description'
128-
>
129-
<DialogTitle id='alert-dialog-title'>{'Clear form?'}</DialogTitle>
130-
<DialogContent>
131-
<DialogContentText id='alert-dialog-description'>
132-
Your data will be cleared if you navigate away from this tab. Do you
133-
want to proceed?
134-
</DialogContentText>
135-
</DialogContent>
136-
<DialogActions>
137-
<Button onClick={cancel} color='primary'>
138-
No
139-
</Button>
140-
<Button
141-
onClick={confirm}
142-
color='primary'
143-
autoFocus
144-
id={`oneOf-${id}-confirm-yes`}
145-
>
146-
Yes
147-
</Button>
148-
</DialogActions>
149-
</Dialog>
150-
</Hidden>
151-
);
152-
};
91+
return (
92+
<Hidden xsUp={!visible}>
93+
<CombinatorProperties
94+
schema={_schema}
95+
combinatorKeyword={'oneOf'}
96+
path={path}
97+
/>
98+
<Tabs value={selectedIndex} onChange={handleTabChange}>
99+
{oneOfRenderInfos.map(oneOfRenderInfo => <Tab key={oneOfRenderInfo.label} label={oneOfRenderInfo.label} />)}
100+
</Tabs>
101+
{
102+
oneOfRenderInfos.map((oneOfRenderInfo, oneOfIndex) => (
103+
selectedIndex === oneOfIndex && (
104+
<JsonFormsDispatch
105+
key={oneOfIndex}
106+
schema={oneOfRenderInfo.schema}
107+
uischema={oneOfRenderInfo.uischema}
108+
path={path}
109+
renderers={renderers}
110+
/>
111+
)
112+
))
113+
}
114+
<Dialog
115+
open={open}
116+
onClose={handleClose}
117+
aria-labelledby='alert-dialog-title'
118+
aria-describedby='alert-dialog-description'
119+
>
120+
<DialogTitle id='alert-dialog-title'>{'Clear form?'}</DialogTitle>
121+
<DialogContent>
122+
<DialogContentText id='alert-dialog-description'>
123+
Your data will be cleared if you navigate away from this tab.
124+
Do you want to proceed?
125+
</DialogContentText>
126+
</DialogContent>
127+
<DialogActions>
128+
<Button onClick={cancel} color='primary'>
129+
No
130+
</Button>
131+
<Button onClick={confirm} color='primary' autoFocus id={`oneOf-${id}-confirm-yes`}>
132+
Yes
133+
</Button>
134+
</DialogActions>
135+
</Dialog>
136+
</Hidden>
137+
);
138+
};
153139

154-
export const materialOneOfControlTester: RankedTester = rankWith(
155-
3,
156-
isOneOfControl
157-
);
140+
export const materialOneOfControlTester: RankedTester = rankWith(3, isOneOfControl);
158141
export default withJsonFormsOneOfProps(MaterialOneOfRenderer);

packages/material/test/renderers/MaterialGroupLayout.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ const uischema = {
4141

4242
describe('Material group layout', () => {
4343
it('should render a GroupComponent with direction column when given no direction LayoutProp', () => {
44-
const wrapper = mount(<MaterialGroupLayout schema={schema} uischema={uischema} />)
45-
expect(wrapper.find(MaterialLayoutRenderer).props().direction).toBe('column')
44+
const wrapper = mount(<MaterialGroupLayout schema={schema} uischema={uischema} />);
45+
expect(wrapper.find(MaterialLayoutRenderer).props().direction).toBe('column');
4646
})
4747

4848
it('should render a GroupComponent with direction row when this is provided as a direction prop', () => {
49-
const wrapper = mount(<MaterialGroupLayout schema={schema} uischema={uischema} direction={'row'} />)
50-
expect(wrapper.find(MaterialLayoutRenderer).props().direction).toBe('row')
49+
const wrapper = mount(<MaterialGroupLayout schema={schema} uischema={uischema} direction={'row'} />);
50+
expect(wrapper.find(MaterialLayoutRenderer).props().direction).toBe('row');
5151
})
5252
})

packages/react/src/JsonForms.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,8 @@ export class ResolvedJsonFormsDispatchRenderer
6161
prevState: JsonFormsRendererState
6262
) {
6363

64-
const schemaHasRefs: boolean = hasRefs(nextProps.schema);
65-
6664
if (!isEqual(prevState.schema, nextProps.schema)) {
65+
const schemaHasRefs: boolean = hasRefs(nextProps.schema);
6766
const newState: JsonFormsRendererState = {
6867
id: prevState.id,
6968
resolvedSchema: schemaHasRefs ? undefined : nextProps.schema,
@@ -179,6 +178,7 @@ export interface JsonFormsInitStateProps {
179178

180179
export const JsonForms = (props: JsonFormsInitStateProps) => {
181180
const { data, schema, uischema, renderers } = props;
181+
182182
return (
183183
<JsonFormsStateProvider
184184
initState={{

0 commit comments

Comments
 (0)