Skip to content

Commit

Permalink
Rework JsonFormsStateProvider
Browse files Browse the repository at this point in the history
 * Initialize with Actions.init instead of delaying it
 * Reuse the config reducer

Initializing with Actions.init avoids invalid core states as we assume
that Actions.init was called from the very beginning. Usually these
invalid core states don't have consequences however sometimes the app
crashed (see #1539).

Reusing the config reducer makes sure that the config always contains at
least the default values.
  • Loading branch information
sdirix committed May 13, 2020
1 parent ac47bb8 commit e77463f
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 78 deletions.
16 changes: 7 additions & 9 deletions packages/core/src/actions/index.ts
Expand Up @@ -23,12 +23,12 @@
THE SOFTWARE.
*/
import AJV, { ErrorObject } from 'ajv';
import RefParser from 'json-schema-ref-parser';
import { RankedTester } from '../testers';
import { JsonSchema, UISchemaElement } from '../';
import { generateDefaultUISchema, generateJsonSchema } from '../generators';

import { RankedTester } from '../testers';
import RefParser from 'json-schema-ref-parser';
import { UISchemaTester } from '../reducers/uischemas';
import { AnyAction, Dispatch } from 'redux';

export const INIT: 'jsonforms/INIT' = 'jsonforms/INIT';
export const SET_AJV: 'jsonforms/SET_AJV' = 'jsonforms/SET_AJV';
Expand Down Expand Up @@ -201,12 +201,10 @@ export interface SetConfigAction {
config: any;
}

export const setConfig = (config: any) => (dispatch: Dispatch<AnyAction>) => {
dispatch({
type: SET_CONFIG,
config
});
};
export const setConfig = (config: any) => ({
type: SET_CONFIG,
config,
});

export type UISchemaActions = AddUISchemaAction | RemoveUISchemaAction;

Expand Down
75 changes: 38 additions & 37 deletions packages/core/src/reducers/index.ts
@@ -1,3 +1,39 @@
import { ControlElement, UISchemaElement } from '../models/uischema';
import {
JsonFormsCore,
coreReducer,
errorAt,
errorsAt,
extractData,
extractRefParserOptions,
extractSchema,
extractUiSchema,
subErrorsAt
} from './core';
import {
JsonFormsDefaultDataRegistryEntry,
defaultDataReducer,
extractDefaultData
} from './default-data';
import { JsonFormsRendererRegistryEntry, rendererReducer } from './renderers';
import { JsonFormsState, JsonFormsSubStates } from '../store';
import { Reducer, combineReducers } from 'redux';
import {
UISchemaTester,
findMatchingUISchema,
uischemaRegistryReducer
} from './uischemas';
import {
fetchLocale,
findLocalizedSchema,
findLocalizedUISchema,
i18nReducer
} from './i18n';

import { Generate } from '../generators';
import { JsonFormsCellRendererRegistryEntry } from './cells';
import { JsonSchema } from '../models/jsonSchema';
import RefParser from 'json-schema-ref-parser';
/*
The MIT License
Expand All @@ -23,50 +59,15 @@
THE SOFTWARE.
*/
import { cellReducer } from './cells';
import get from 'lodash/get';
import {
defaultDataReducer,
extractDefaultData,
JsonFormsDefaultDataRegistryEntry
} from './default-data';
import { combineReducers, Reducer } from 'redux';
import { JsonFormsRendererRegistryEntry, rendererReducer } from './renderers';
import RefParser from 'json-schema-ref-parser';
import { configReducer } from './config';
import {
coreReducer,
errorAt,
errorsAt,
extractData,
extractRefParserOptions,
extractSchema,
extractUiSchema,
JsonFormsCore,
subErrorsAt
} from './core';
import { JsonFormsState, JsonFormsSubStates } from '../store';
import {
findMatchingUISchema,
uischemaRegistryReducer,
UISchemaTester
} from './uischemas';
import {
fetchLocale,
findLocalizedSchema,
findLocalizedUISchema,
i18nReducer
} from './i18n';

import { JsonSchema } from '../models/jsonSchema';
import { ControlElement, UISchemaElement } from '../models/uischema';
import { Generate } from '../generators';
import { JsonFormsCellRendererRegistryEntry } from './cells';
import get from 'lodash/get';

export {
rendererReducer,
cellReducer,
coreReducer,
i18nReducer,
configReducer,
UISchemaTester,
uischemaRegistryReducer,
findMatchingUISchema
Expand Down
2 changes: 1 addition & 1 deletion packages/example/src/reduxUtil.ts
Expand Up @@ -84,7 +84,7 @@ const mapDispatchToProps = (dispatch: Dispatch<AnyAction>) => ({
changeExampleData: (example: ReactExampleDescription) => {
dispatch(changeExample(example));
dispatch(Actions.init(example.data, example.schema, example.uischema));
Actions.setConfig(example.config)(dispatch);
dispatch(Actions.setConfig(example.config));
},
getComponent: (example: ReactExampleDescription) =>
example.customReactExtension
Expand Down
96 changes: 65 additions & 31 deletions packages/react/src/JsonFormsContext.tsx
Expand Up @@ -23,55 +23,55 @@
THE SOFTWARE.
*/

import React, { ComponentType, Dispatch, ReducerAction, useCallback, useContext, useEffect, useReducer } from 'react';
import isEqual from 'lodash/isEqual';
import omit from 'lodash/omit';
import get from 'lodash/get';
import {
Actions,
ArrayControlProps,
ArrayLayoutProps,
CellProps,
CombinatorProps,
ControlProps,
coreReducer,
DispatchCellProps,
DispatchPropsOfControl,
EnumCellProps,
JsonFormsCore,
JsonFormsState,
JsonFormsSubStates,
LayoutProps,
OwnPropsOfCell,
OwnPropsOfControl,
OwnPropsOfEnum,
OwnPropsOfEnumCell,
OwnPropsOfJsonFormsRenderer,
OwnPropsOfLayout,
OwnPropsOfMasterListItem,
OwnPropsOfRenderer,
StatePropsOfCombinator,
StatePropsOfControlWithDetail,
StatePropsOfMasterItem,
configReducer,
coreReducer,
mapDispatchToArrayControlProps,
mapStateToAllOfProps,
mapStateToAnyOfProps,
mapStateToArrayControlProps,
mapStateToArrayLayoutProps,
mapStateToCellProps,
mapStateToControlProps,
mapStateToEnumControlProps,
mapStateToControlWithDetailProps,
mapStateToDispatchCellProps,
mapStateToEnumControlProps,
mapStateToJsonFormsRendererProps,
mapStateToLayoutProps,
mapStateToMasterListItemProps,
mapStateToOneOfProps,
OwnPropsOfCell,
OwnPropsOfControl,
OwnPropsOfEnum,
OwnPropsOfEnumCell,
OwnPropsOfJsonFormsRenderer,
OwnPropsOfMasterListItem,
rendererReducer,
StatePropsOfCombinator,
StatePropsOfControlWithDetail,
StatePropsOfMasterItem,
update,
OwnPropsOfLayout,
OwnPropsOfRenderer,
DispatchCellProps,
mapStateToDispatchCellProps,
cellReducer
update
} from '@jsonforms/core';
import React, { ComponentType, Dispatch, ReducerAction, useCallback, useContext, useEffect, useReducer, useRef } from 'react';

import { connect } from 'react-redux';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import omit from 'lodash/omit';

const initialCoreState: JsonFormsCore = {
data: {},
Expand All @@ -92,23 +92,57 @@ export const JsonFormsContext = React.createContext<JsonFormsStateContext>({
renderers: []
});

/**
* Hook similar to `useEffect` with the difference that the effect
* is only executed from the second call onwards.
*/
const useEffectAfterFirstRender = (
effect: () => void,
dependencies: Array<any>
) => {
const firstExecution = useRef(true);
useEffect(() => {
if (firstExecution.current) {
firstExecution.current = false;
return;
}
effect();
}, dependencies);
};

export const JsonFormsStateProvider = ({ children, initState }: any) => {
const [core, dispatch] = useReducer(coreReducer, initState.core);
const [renderers] = useReducer(rendererReducer, initState.renderers);
const [cells] = useReducer(cellReducer, initState.cells);
const { data, schema, uischema, ajv, refParserOptions } = initState.core;
useEffect(() => {
dispatch(Actions.init(data, schema, uischema, { ajv, refParserOptions }));
// Initialize core immediatly
const [core, coreDispatch] = useReducer(
coreReducer,
coreReducer(
initState.core,
Actions.init(data, schema, uischema, { ajv, refParserOptions })
)
);
useEffectAfterFirstRender(() => {
coreDispatch(
Actions.init(data, schema, uischema, { ajv, refParserOptions })
);
}, [data, schema, uischema, ajv, refParserOptions]);

const [config, configDispatch] = useReducer(
configReducer,
configReducer(undefined, Actions.setConfig(initState.config))
);
useEffectAfterFirstRender(() => {
configDispatch(Actions.setConfig(initState.config));
}, [initState.config]);

return (
<JsonFormsContext.Provider
value={{
core,
renderers,
cells,
config: initState.config,
renderers: initState.renderers,
cells: initState.cells,
config: config,
// only core dispatch available
dispatch,
dispatch: coreDispatch,
}}
>
{children}
Expand Down

0 comments on commit e77463f

Please sign in to comment.