Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/components/JsonSchemaViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isRegularNode, SchemaTree as JsonSchemaTree, SchemaTreeRefDereferenceFn } from '@stoplight/json-schema-tree';
import type { WalkerEmitter, WalkerNodeEventHandler } from '@stoplight/json-schema-tree/walker';
import { Box, Provider as MosaicProvider } from '@stoplight/mosaic';
import { ErrorBoundaryForwardedProps, FallbackProps, withErrorBoundary } from '@stoplight/react-error-boundary';
import cn from 'classnames';
Expand All @@ -14,6 +15,11 @@ export type JsonSchemaProps = Partial<JSVOptions> & {
emptyText?: string;
className?: string;
resolveRef?: SchemaTreeRefDereferenceFn;
treeWalkerEventEmitter?: {
event: keyof WalkerEmitter;
handler: WalkerNodeEventHandler;
};
onTreePopulated?: (tree: JsonSchemaTree) => void;
};

const JsonSchemaViewerComponent: React.FC<JsonSchemaProps & ErrorBoundaryForwardedProps> = ({
Expand All @@ -26,12 +32,19 @@ const JsonSchemaViewerComponent: React.FC<JsonSchemaProps & ErrorBoundaryForward
onGoToRef,
renderRowAddon,
hideExamples,
treeWalkerEventEmitter,
onTreePopulated,
}) => {
const jsonSchemaTreeRoot = React.useMemo(() => {
const jsonSchemaTree = new JsonSchemaTree(schema, {
mergeAllOf: true,
refResolver: resolveRef,
});

if (treeWalkerEventEmitter) {
jsonSchemaTree.walker.on(treeWalkerEventEmitter.event, treeWalkerEventEmitter.handler);
}

jsonSchemaTree.walker.hookInto('filter', node => {
if (!isRegularNode(node)) return true;

Expand All @@ -44,8 +57,9 @@ const JsonSchemaViewerComponent: React.FC<JsonSchemaProps & ErrorBoundaryForward
return !((viewMode === 'read' && !!validations.writeOnly) || (viewMode === 'write' && !!validations.readOnly));
});
jsonSchemaTree.populate();
onTreePopulated?.(jsonSchemaTree);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that this useMemo is quite side-effect'y already, but we really shouldn't do that.

Simple refactor would allow for that function to be called in a separate useEffect hook.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate more on what kind of refactor you have in mind?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tracking isPopulated state and then using that in useEffect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I guess I could just use jsonSchemaTreeRoot as dependency, I will try it out

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useMemo can return the whole jsonSchemaTree.

Than you just make useEffect where that callback is called with jsonSchemaTree 🤷

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like:

const jsonSchemaTree = React.useMemo(...);

React.useEffect(() => {
   onTreePopulated?.(jsonSchemaTree);
}, [jsonSchemaTree, onTreePopulated]);

return jsonSchemaTree.root;
}, [schema, resolveRef, viewMode]);
}, [schema, resolveRef, viewMode, treeWalkerEventEmitter, onTreePopulated]);

const isEmpty = React.useMemo(() => jsonSchemaTreeRoot.children.every(node => !isRegularNode(node) || node.unknown), [
jsonSchemaTreeRoot,
Expand Down