From e8bb2fdc980298d0a732f1f18ee63aeacb97ab14 Mon Sep 17 00:00:00 2001 From: Stefan Dirix Date: Tue, 7 Nov 2023 13:36:49 +0100 Subject: [PATCH] wip: JSON Forms middleware support Showcase of middleware support in JSON Forms React. Not tested at all. --- packages/react/src/JsonForms.tsx | 5 ++ packages/react/src/JsonFormsContext.tsx | 61 +++++++++++++++++++------ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/packages/react/src/JsonForms.tsx b/packages/react/src/JsonForms.tsx index 7d06bcd8c..8b4856ada 100644 --- a/packages/react/src/JsonForms.tsx +++ b/packages/react/src/JsonForms.tsx @@ -28,6 +28,7 @@ import type Ajv from 'ajv'; import type { ErrorObject } from 'ajv'; import { UnknownRenderer } from './UnknownRenderer'; import { + CoreActions, createId, Generate, isControl, @@ -45,6 +46,7 @@ import { } from '@jsonforms/core'; import { JsonFormsStateProvider, + Middleware, withJsonFormsRendererProps, } from './JsonFormsContext'; @@ -54,6 +56,7 @@ interface JsonFormsRendererState { export interface JsonFormsReactProps { onChange?(state: Pick): void; + middleware?: Middleware; } export class JsonFormsDispatchRenderer extends React.Component< @@ -203,6 +206,7 @@ export const JsonForms = ( validationMode, i18n, additionalErrors, + middleware, } = props; const schemaToUse = useMemo( () => (schema !== undefined ? schema : Generate.jsonSchema(data)), @@ -233,6 +237,7 @@ export const JsonForms = ( i18n, }} onChange={onChange} + middleware={middleware} > diff --git a/packages/react/src/JsonFormsContext.tsx b/packages/react/src/JsonFormsContext.tsx index b860f6a91..a25e39299 100644 --- a/packages/react/src/JsonFormsContext.tsx +++ b/packages/react/src/JsonFormsContext.tsx @@ -75,6 +75,7 @@ import { OwnPropsOfLabel, LabelProps, mapStateToLabelProps, + CoreActions, } from '@jsonforms/core'; import debounce from 'lodash/debounce'; import React, { @@ -87,6 +88,7 @@ import React, { useMemo, useReducer, useRef, + useState, } from 'react'; const initialCoreState: JsonFormsCore = { @@ -126,33 +128,59 @@ const useEffectAfterFirstRender = ( }, dependencies); }; +export interface Middleware { + ( + state: JsonFormsCore, + action: CoreActions, + defaultDispatch: ( + state: JsonFormsCore, + action: CoreActions + ) => JsonFormsCore + ): JsonFormsCore; +} + +const defaultMiddleware: Middleware = (state, action, defaultDispatch) => + defaultDispatch(state, action); + export const JsonFormsStateProvider = ({ children, initState, onChange, + middleware, }: any) => { const { data, schema, uischema, ajv, validationMode, additionalErrors } = initState.core; - const [core, coreDispatch] = useReducer(coreReducer, undefined, () => - coreReducer( + const middlewareRef = useRef(middleware ?? defaultMiddleware); + middlewareRef.current = middleware ?? defaultMiddleware; + + const [core, setCore] = useState(() => + middlewareRef.current( initState.core, Actions.init(data, schema, uischema, { ajv, validationMode, additionalErrors, - }) + }), + coreReducer ) ); - useEffect(() => { - coreDispatch( - Actions.updateCore(data, schema, uischema, { - ajv, - validationMode, - additionalErrors, - }) - ); - }, [data, schema, uischema, ajv, validationMode, additionalErrors]); + + useEffect( + () => + setCore((currentCore) => + middlewareRef.current( + currentCore, + Actions.updateCore(data, schema, uischema, { + ajv, + validationMode, + additionalErrors, + }), + coreReducer + ) + ), + [data, schema, uischema, ajv, validationMode, additionalErrors] + ); const [config, configDispatch] = useReducer(configReducer, undefined, () => configReducer(undefined, Actions.setConfig(initState.config)) @@ -185,6 +213,12 @@ export const JsonFormsStateProvider = ({ initState.i18n?.translateError, ]); + const dispatch = useCallback((action: CoreActions) => { + setCore((currentCore) => + middlewareRef.current(currentCore, action, coreReducer) + ); + }, []); + const contextValue = useMemo( () => ({ core, @@ -194,8 +228,7 @@ export const JsonFormsStateProvider = ({ uischemas: initState.uischemas, readonly: initState.readonly, i18n: i18n, - // only core dispatch available - dispatch: coreDispatch, + dispatch: dispatch, }), [ core,