Summary
In the process of developing custom renderers for Gutenberg Components, I want to integrate Navigator Component because I want to display nested props on separate views and only use single schema
To render the Navigator Component markup] requires the form screens in on a flat structure, therefore current jsonforms renders the nested props in nested markup.
ObjectRenderer update its screen via context and only display the NavigatorButton
The new NavigatorLayout renderer receives the screen content from nested props and render its list of NavigatorScreen
Though this approach works well as you can see in the attached recording above, as it is compatible with jsonforms current features set such as show/hide rules, you may see the obvious issue here with Context usage: Provider and Consumer unnecessary re-rendering
useEffect(() => {
// Use the callback since the new state is based on the previous state
setScreenContent(prevScreenContent => ({
...prevScreenContent,
[route]: {
component: (<JsonFormsDispatch
visible={visible}
enabled={enabled}
schema={schema}
uischema={detailUiSchema}
path={path}
renderers={renderers}
cells={cells}
/>),
label: detailUiSchema.label,
path: path
}
}))
}, [route])
I hope you can help me to improve the context usage to optimize the app and if there is built-in feature that can help achieve the similar requirements (render nested object in flat structure), I am happy to know
The original question was about the need of a uischema generator to get all the form screens from root node,
[…]
if there is built-in feature that can help achieve the similar requirements (render nested object in flat structure)
The nested rendering happens because:
Every nested object is rendered by the object renderer
The object renderer generates a UI Schema for the object and dispatches again
The generated UI Schema is a Group which is why it looks nested
An easy way to render flat lists therefore is to overwrite the generic Group renderer with an own implementation and simply let it generate a VerticalLayout instead of a Group. In the DOM the controls will still be nested in layout divs, however by default the VerticalLayout has no margin nor padding so it is not visible.
As an alternative you could of course adapt the UI Schema generation more deeply and instead of rendering nested objects via an object control, look further into them and generate controls for the nested properties directly.
I hope you can help me to improve the context usage to optimize the app
The used approach can’t be optimized as it rerenders by design, i.e. the parent component is informed about new elements during rendering of one of its children. This will always rerender no matter what you do. With the usage of React.memo parts of it could be improved, but the overall issue will remain.
The clean solution is to get rid off the context and determine beforehand which screens you want to show. As the screens are aligned with the use of objects this can be analyzed beforehand in a straightforward manner. Did you try the approach which I suggested here?
Actually I am concern about the nested DOM nodes, while the NavigatorProvider of Gutenberg requires all the screens to be on the same level of the main screen, that why I am looking for effective way so that all the deep nested screens can be rendered on the root node, which requires a deep generated UISchema or context. ( again, am I missing a built-in feature that can do that? )
I am aware context makes providers and consumers re-rendered by design, but I will try to improve performance using useMemo somehow
Attached is the recording of what have been implemented
You still don’t need deeply generated UI schemas for the deeply nested cases. You just need to hand over the parameters to the JSON Dispatch accordingly.
Should look something like this. Note that I wrote this down without testing. Code can obviously be optimized to not join the path array all the time, etc.
Edit: Note that for the objects contained within you want to have a custom object renderer which replaces nested object rendering with NavigatorButtons. You can then either determine the NavigatorButton’s path by converting your props, or you make the screenInformation available via a context from the NavigatorLayoutRenderer. This is fine here as the context is created once and not modified on the fly during rendering.
Yeah I agreed, this is also my approach to not lean on the deep nested uischema, as described I let the nested props generate its own uischema and pass to root via context