From d32832df6b2a5082532b7dc89c263265e178514d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Fri, 14 Jun 2019 18:17:21 +0800 Subject: [PATCH 1/2] feat: make JSV recoverable from error state --- package.json | 3 +- src/components/JsonSchemaViewer.tsx | 49 ++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 9a5bde64..9da9e52a 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,7 @@ "classnames": "^2.2.6", "json-schema-merge-allof": "^0.6.0", "mobx-react-lite": "^1.3.1", - "pluralize": "^7.0.0", - "react-error-boundary": "^1.2.5" + "pluralize": "^7.0.0" }, "devDependencies": { "@sambego/storybook-state": "^1.3.4", diff --git a/src/components/JsonSchemaViewer.tsx b/src/components/JsonSchemaViewer.tsx index 823e9112..20c91473 100644 --- a/src/components/JsonSchemaViewer.tsx +++ b/src/components/JsonSchemaViewer.tsx @@ -2,14 +2,15 @@ import { TreeStore } from '@stoplight/tree-list'; import * as cn from 'classnames'; import { runInAction } from 'mobx'; import * as React from 'react'; -import ErrorBoundary, { ErrorBoundaryProps, FallbackProps } from 'react-error-boundary'; import { JSONSchema4 } from 'json-schema'; import { GoToRefHandler } from '../types'; import { isSchemaViewerEmpty, renderSchema } from '../utils'; import { SchemaTree } from './SchemaTree'; -export interface IJsonSchemaViewer extends ErrorBoundaryProps { +export type FallbackComponent = React.ComponentType<{ error: Error | null }>; + +export interface IJsonSchemaViewer { schema: JSONSchema4; dereferencedSchema?: JSONSchema4; style?: object; @@ -21,6 +22,7 @@ export interface IJsonSchemaViewer extends ErrorBoundaryProps { hideTopBar?: boolean; maxRows?: number; onGoToRef?: GoToRefHandler; + FallbackComponent?: FallbackComponent; } export class JsonSchemaViewerComponent extends React.PureComponent { @@ -86,7 +88,7 @@ export class JsonSchemaViewerComponent extends React.PureComponent = ({ error }) => { +const JsonSchemaFallbackComponent: FallbackComponent = ({ error }) => { return (
Error @@ -95,15 +97,32 @@ const JsonSchemaFallbackComponent: React.FunctionComponent = ({ e ); }; -export const JsonSchemaViewer: React.FunctionComponent = ({ - onError, - FallbackComponent = JsonSchemaFallbackComponent, - ...props -}) => { - return ( - - - - ); -}; -JsonSchemaViewer.displayName = 'JsonSchemaViewer'; +// react-error-boundary does not support recovering, see https://github.com/bvaughn/react-error-boundary/pull/16/files +export class JsonSchemaViewer extends React.PureComponent { + public state = { + error: null, + }; + + public componentDidUpdate(prevProps: Readonly) { + if ( + this.state.error !== null && + (prevProps.schema !== this.props.schema || prevProps.dereferencedSchema !== this.props.dereferencedSchema) + ) { + this.setState({ error: null }); + } + } + + // there is no error hook yet, see https://reactjs.org/docs/hooks-faq.html#how-do-lifecycle-methods-correspond-to-hooks + public static getDerivedStateFromError(error: Error) { + return { error }; + } + + public render() { + const { FallbackComponent: Fallback = JsonSchemaFallbackComponent, ...props } = this.props; + if (this.state.error) { + return ; + } + + return ; + } +} From ab2e1ef562a6fc3fd72e14cfa0e711b8c3540436 Mon Sep 17 00:00:00 2001 From: William Hilton Date: Fri, 14 Jun 2019 14:48:58 -0400 Subject: [PATCH 2/2] chore: add error recovery demonstration to Storybook --- src/__stories__/JsonSchemaViewer.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/__stories__/JsonSchemaViewer.tsx b/src/__stories__/JsonSchemaViewer.tsx index f7591393..0950b0c8 100644 --- a/src/__stories__/JsonSchemaViewer.tsx +++ b/src/__stories__/JsonSchemaViewer.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { State, Store } from '@sambego/storybook-state'; import { action } from '@storybook/addon-actions'; -import { boolean, number, object, text, withKnobs } from '@storybook/addon-knobs'; +import { boolean, number, object, select, text, withKnobs } from '@storybook/addon-knobs'; import { storiesOf } from '@storybook/react'; import { JsonSchemaViewer } from '../components'; @@ -80,7 +80,14 @@ storiesOf('JsonSchemaViewer', module) console.log('You can hook into the onError handler too!', error)} expanded={boolean('expanded', false)} defaultExpandedDepth={number('defaultExpandedDepth', 2)}