formio / react

JSON powered forms for React.js
https://form.io
MIT License
311 stars 271 forks source link

[BUG] Custom component unmounting #485

Open FractalStranger opened 1 year ago

FractalStranger commented 1 year ago

Hi,

I have a React18 project and wanted to make custom react-formio component (code below) but this.container.unmount in detachReact method shows this warning:

Warning: Attempted to synchronously unmount a root while React was already rendering. React cannot finish unmounting the root until the current render has completed, which may lead to a race condition.

is there any way to unmount the element without the warning? (And is react-formio compatible with React 18 overall?)

Thanks.

Code:

export default class Grid extends ReactComponent {
  ...
  ...

  attachReact(element) {
    this.container = createRoot(element)
    return this.container.render(
      <HistoryRouter history={history}>
        <GridComponent {...{ ...this }} />
      </HistoryRouter>
    )
  }

  detachReact(element) {
    if (element) {
      this.container.unmount() // this creates the race condition warning
    }
  }
}

Environment

aryanisml commented 1 year ago

Do u have any example of custom component with react typescript if yes please share.

FractalStranger commented 1 year ago

Typescript? Does react-formio support Typescript? It doesn't seem so.

Here is the code of custom component: https://jsfiddle.net/kv0tq9p8/

govind15496 commented 1 year ago

Hey I am a newcomer in this project and I would like to contribute

mtruon11 commented 1 year ago

Hi,

I have a React18 project and wanted to make custom react-formio component (code below) but this.container.unmount in detachReact method shows this warning:

Warning: Attempted to synchronously unmount a root while React was already rendering. React cannot finish unmounting the root until the current render has completed, which may lead to a race condition.

is there any way to unmount the element without the warning? (And is react-formio compatible with React 18 overall?)

Thanks.

Code:

export default class Grid extends ReactComponent {
  ...
  ...

  attachReact(element) {
    this.container = createRoot(element)
    return this.container.render(
      <HistoryRouter history={history}>
        <GridComponent {...{ ...this }} />
      </HistoryRouter>
    )
  }

  detachReact(element) {
    if (element) {
      this.container.unmount() // this creates the race condition warning
    }
  }
}

Environment

  • Hosting type

    • [ ] Form.io

    • [x] Local deployment

    • Version:

  • Formio.js version: 5.0.0-m.3
  • Frontend framework: React 18

I wonder if you can share your GridComponent code? I am trying to implement it myself but I am not sure how to start.

lotorvik commented 1 year ago

@FractalStranger did you figure any way to get around this?

YoungDriverOfTech commented 6 months ago

@FractalStranger Hello, did you find someway to figure this out yet? Same issue I also encoutered.

brendanbond commented 3 months ago

Hey @YoungDriverOfTech @lotorvik @FractalStranger thanks for chiming in here. A couple of things to consider:

  1. I would consider this functionality (in which a react rendering context/instance is "embedded" into a @formio/js render cycle) to really be experimental; my guess is that we're not going to fully support this at any point in the near future. It requires a pretty in-depth knowledge of form.io internals at the moment - for example, we use the "ref" attribute for different reasons than React does so it becomes necessary to change the name of our "ref" attribute so React doesn't complain - and I'm not aware of any plans to clean up the APIs so that something like this would be more easily possible.
  2. We've made some updates in the development branch (in our org, that is master) that refactor the @formio/react library for Typescript and React 18 support. They'll be released with the 5.x version of @formio/js, which is not that far off but still is in development.
  3. I've done some of my own experimenting with this, and here's a file that shows how one might accomplish something like this in React 18 using some of the new changes to @formio/react (and the beta 5.x version of the @formio/js renderer). Keep in mind that there are no guarantees here (see above) and that this is all just experimentation.
    
    import React from 'react';
    import { Components } from '@formio/js';
    import { Root, createRoot } from 'react-dom/client';
    import { TextFieldWrapper } from './TextFieldWrapper';

type JSON = string | number | boolean | null | { [x: string]: JSON } | JSON[];

const Field = Components.components.field; export class MUITextField extends Field { reactRendered: boolean; reactRoot: Root | null; /**