Skip to content

Commit a4c8e9c

Browse files
committed
feat: middleware support in React bindings
This update introduces optional middleware support for our React bindings, enabling advanced features like controlled mode in JSON Forms and on-the-fly handling of derived attributes.
1 parent 18c0825 commit a4c8e9c

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

packages/react/src/JsonForms.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
} from '@jsonforms/core';
4646
import {
4747
JsonFormsStateProvider,
48+
Middleware,
4849
withJsonFormsRendererProps,
4950
} from './JsonFormsContext';
5051

@@ -54,6 +55,7 @@ interface JsonFormsRendererState {
5455

5556
export interface JsonFormsReactProps {
5657
onChange?(state: Pick<JsonFormsCore, 'data' | 'errors'>): void;
58+
middleware?: Middleware;
5759
}
5860

5961
export class JsonFormsDispatchRenderer extends React.Component<
@@ -203,6 +205,7 @@ export const JsonForms = (
203205
validationMode,
204206
i18n,
205207
additionalErrors,
208+
middleware,
206209
} = props;
207210
const schemaToUse = useMemo(
208211
() => (schema !== undefined ? schema : Generate.jsonSchema(data)),
@@ -235,6 +238,7 @@ export const JsonForms = (
235238
i18n,
236239
}}
237240
onChange={onChange}
241+
middleware={middleware}
238242
>
239243
<JsonFormsDispatch />
240244
</JsonFormsStateProvider>

packages/react/src/JsonFormsContext.tsx

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import {
7575
OwnPropsOfLabel,
7676
LabelProps,
7777
mapStateToLabelProps,
78+
CoreActions,
7879
} from '@jsonforms/core';
7980
import debounce from 'lodash/debounce';
8081
import React, {
@@ -87,6 +88,7 @@ import React, {
8788
useMemo,
8889
useReducer,
8990
useRef,
91+
useState,
9092
} from 'react';
9193

9294
const initialCoreState: JsonFormsCore = {
@@ -126,33 +128,56 @@ const useEffectAfterFirstRender = (
126128
}, dependencies);
127129
};
128130

131+
export interface Middleware {
132+
(
133+
state: JsonFormsCore,
134+
action: CoreActions,
135+
defaultReducer: (state: JsonFormsCore, action: CoreActions) => JsonFormsCore
136+
): JsonFormsCore;
137+
}
138+
139+
const defaultMiddleware: Middleware = (state, action, defaultReducer) =>
140+
defaultReducer(state, action);
141+
129142
export const JsonFormsStateProvider = ({
130143
children,
131144
initState,
132145
onChange,
146+
middleware,
133147
}: any) => {
134148
const { data, schema, uischema, ajv, validationMode, additionalErrors } =
135149
initState.core;
136150

137-
const [core, coreDispatch] = useReducer(coreReducer, undefined, () =>
138-
coreReducer(
151+
const middlewareRef = useRef<Middleware>(middleware ?? defaultMiddleware);
152+
middlewareRef.current = middleware ?? defaultMiddleware;
153+
154+
const [core, setCore] = useState<JsonFormsCore>(() =>
155+
middlewareRef.current(
139156
initState.core,
140157
Actions.init(data, schema, uischema, {
141158
ajv,
142159
validationMode,
143160
additionalErrors,
144-
})
161+
}),
162+
coreReducer
145163
)
146164
);
147-
useEffect(() => {
148-
coreDispatch(
149-
Actions.updateCore(data, schema, uischema, {
150-
ajv,
151-
validationMode,
152-
additionalErrors,
153-
})
154-
);
155-
}, [data, schema, uischema, ajv, validationMode, additionalErrors]);
165+
166+
useEffect(
167+
() =>
168+
setCore((currentCore) =>
169+
middlewareRef.current(
170+
currentCore,
171+
Actions.updateCore(data, schema, uischema, {
172+
ajv,
173+
validationMode,
174+
additionalErrors,
175+
}),
176+
coreReducer
177+
)
178+
),
179+
[data, schema, uischema, ajv, validationMode, additionalErrors]
180+
);
156181

157182
const [config, configDispatch] = useReducer(configReducer, undefined, () =>
158183
configReducer(undefined, Actions.setConfig(initState.config))
@@ -185,6 +210,12 @@ export const JsonFormsStateProvider = ({
185210
initState.i18n?.translateError,
186211
]);
187212

213+
const dispatch = useCallback((action: CoreActions) => {
214+
setCore((currentCore) =>
215+
middlewareRef.current(currentCore, action, coreReducer)
216+
);
217+
}, []);
218+
188219
const contextValue = useMemo(
189220
() => ({
190221
core,
@@ -194,8 +225,7 @@ export const JsonFormsStateProvider = ({
194225
uischemas: initState.uischemas,
195226
readonly: initState.readonly,
196227
i18n: i18n,
197-
// only core dispatch available
198-
dispatch: coreDispatch,
228+
dispatch: dispatch,
199229
}),
200230
[
201231
core,

0 commit comments

Comments
 (0)