react-jsonschema-form icon indicating copy to clipboard operation
react-jsonschema-form copied to clipboard

Editing widget type breaks the app

Open ForumT opened this issue 6 years ago • 8 comments

Editing widget type breaks the app

I cloned the playground app and it works fine. However when i use the same with the latest react version, then the app breaks while you are editing the schema widget type.

Steps to Reproduce

  1. Clone the playground app..

  2. Select any category like say simple and modify a widget from the UI schema like say age: It is "ui:widget": "updown", I delete updown and before I can type anything, the app breaks with the error:

    Uncaught Error: No widget "" for type "integer"

Expected behavior

The json should show invalid schema and not break the app.

Actual behavior

The app breaks with the error: Uncaught Error: No widget "" for type "integer"

Version

React version 16.3 or higher. React-json-schema-form: 1.0.4

(Modifying just these did not break the app. Still mentioning just in case) codemirror: ^5.39.2 react-codemirror2: ^5.1.0

ForumT avatar Aug 10 '18 07:08 ForumT

I put together a SSCCE with these versions:

It seems to work fine: https://codesandbox.io/s/93kmwl7n7p

I believe this is probably a problem in your environment. If there is another issue, feel free to bring it up.

Otherwise I suggest closing this issue.

loganvolkers avatar Aug 28 '18 19:08 loganvolkers

Thanks for your investigation, @loganvolkers ! I'm closing presumptively. Feel free to re-open if you can reproduce, @ForumT !

glasserc avatar Sep 26 '18 16:09 glasserc

Can we reopen this? I'm having this issue in one of my projects.

I don't know what the codesandbox was trying to reproduce, as the original issue was with ui:widget. I've modified the codesandbox here: https://codesandbox.io/s/charming-cannon-d29tk

Is this not supposed to be handled gracefully by onError?

EDIT

~~Looks like there is a workaround for future readers:~~ https://github.com/rjsf-team/react-jsonschema-form/issues/612

This workaround is not working for me: image

TomKrcmar avatar Oct 26 '19 22:10 TomKrcmar

Sure. @TomKrcmar what behavior do you think should happen instead when a widget is invalid?

epicfaace avatar Oct 27 '19 19:10 epicfaace

@epicfaace I may not be familiar enough with React internals, but I did some debugging, it looks like StringField throws inside its render function due to utils.getWidget - The render function can be called synchronously by a change in state to some higher component, in a call stack that skips my error boundary or even a manual call to ReactDOM.render('Form', ...) inside a try/catch.

Imagine components A -> Boundary -> Form -> StringField - When I call A.setState, StringField throws an error inside its call stack, which does not include Form or Boundary. From what I can tell, It skips my error handling because React queued it previously and rendered it in a beginWork loop triggered by the higher component A. It also doesn't come back in Form.onError. I'm finding it nearly impossible to catch the error without registering a global error handler in index.html that calls e.stopImmediatePropagation and e.preventDefault.

I think this may be related: https://stackoverflow.com/questions/52096804/react-still-showing-errors-after-catching-with-errorboundary https://stackoverflow.com/questions/46589819/disable-error-overlay-in-development-mode/47398520#47398520

React in development mode adds global error handlers that seem to ignore catching & handling, which may explain why the live playground demos don't throw?

--

But to answer your question - Is there some way you're able to catch the error that I'm not aware of? I'm not sure if onError is a suitable place for invalid widget errors, but maybe there's a way to handle this more gracefully?

TomKrcmar avatar Oct 28 '19 03:10 TomKrcmar

@TomKrcmar a more graceful way to handle it would be to do a similar thing to what we do when a schema has an unrecognized type -- see this playground example:

image

Might you be able to make a pull request that fixes this?

epicfaace avatar Dec 09 '19 05:12 epicfaace

@epicfaace The playground crashes upon typing {"title": {}} into the JSONSchema field.

Not an ideal solution, but the error can be caught with an error boundary.

grantzvolsky avatar Aug 09 '21 01:08 grantzvolsky

For those facing an issue, this is what I ended up doing -

create an error boundary like so -

import { Alert } from 'antd';
import * as React from 'react';

interface ErrorProps {
  data?: any;
}

interface ErrorState {
  error: Error | null;
  data: any;
}

export class ErrorBoundary extends React.Component<ErrorProps, ErrorState> {
  constructor(props) {
    super(props);
    this.state = { error: null, data: null };
  }

  static getDerivedStateFromError(error: Error) {
    // Update state so the next render will show the fallback UI.
    return { error: error };
  }

  static getDerivedStateFromProps(props: ErrorProps, state: ErrorState) {
    // We use this data field to ensure that the error state is reset whenever the input data changes.
    // This allows us to have "live updates" to the underlying child components instead of always being
    // stuck in the error state.
    if (props?.data !== state?.data) {
      return { error: null, errorInfo: null, data: props?.data };
    }
    return null;
  }

  render() {
    if (this.state.error) {
      return (
        <Alert
          message={`${this.state.error && this.state.error.toString()}`}
          type='error'
        />
      );
    }
    return this.props.children;
  }
}

You can then use the error boundary like so -

// using ui schema and schema as the data field so that the error boundary is "reset" every time these two are changed
<ErrorBoundary data={JSON.stringify({ uiSchema, schema })}><JSONSchemaForm .../></ErrorBoundary>

sambhav avatar Aug 26 '22 20:08 sambhav