Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editing widget type breaks the app #1002

Closed
ForumT opened this issue Aug 10, 2018 · 8 comments
Closed

Editing widget type breaks the app #1002

ForumT opened this issue Aug 10, 2018 · 8 comments

Comments

@ForumT
Copy link

ForumT commented Aug 10, 2018

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

@loganvolkers
Copy link
Contributor

I put together a SSCCE with these versions:

  • react@16.3.0
  • react-json-schema-form@1.0.4

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.

@glasserc
Copy link
Contributor

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

@TomKrcmar
Copy link

TomKrcmar commented Oct 26, 2019

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:
#612

This workaround is not working for me:
image

@epicfaace epicfaace reopened this Oct 27, 2019
@epicfaace
Copy link
Member

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

@TomKrcmar
Copy link

TomKrcmar commented Oct 28, 2019

@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?

@epicfaace epicfaace changed the title Problem with React v16.3 and higher Editing widget type breaks the app Dec 9, 2019
@epicfaace
Copy link
Member

@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?

@grantzvolsky
Copy link

grantzvolsky commented Aug 9, 2021

@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.

@sambhav
Copy link

sambhav commented Aug 26, 2022

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants