Open FractalStranger opened 1 year ago
Do u have any example of custom component with react typescript if yes please share.
Typescript? Does react-formio support Typescript? It doesn't seem so.
Here is the code of custom component: https://jsfiddle.net/kv0tq9p8/
Hey I am a newcomer in this project and I would like to contribute
Hi,
I have a React18 project and wanted to make custom react-formio component (code below) but
this.container.unmount
indetachReact
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.
@FractalStranger did you figure any way to get around this?
@FractalStranger Hello, did you find someway to figure this out yet? Same issue I also encoutered.
Hey @YoungDriverOfTech @lotorvik @FractalStranger thanks for chiming in here. A couple of things to consider:
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.
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; /**
@param data - The submission data object. */ constructor(component: any, options: any, data: any) { super(component, options, data); this.reactRendered = false; this.reactRoot = null; this._referenceAttributeName = 'data-formioref'; }
/**
components using the this.on() function. */ init() { return super.init(); }
/**
removed. */ destroy() { this.detachReact(); return super.destroy(); }
/**
*/ beforeSubmit() { return super.beforeSubmit(); }
/**
@returns {string} - Returns the full string template of the component
*/
render(): string {
// For React components, we simply render a div which will become the React root.
// By calling super.render(string) it will wrap the component with the needed wrappers to make it a full component.
return super.render(<div data-formioref="react-${this.id}"></div>
);
}
/**
@returns {Promise
if (this.refs[`react-${this.id}`]) {
this.element = this.refs[`react-${this.id}`];
this.attachReact(this.element);
}
return new Promise<void>((resolve) => {
// Wait for the react root to be fully rendered before continuing the attach phase
this.on(`react-rendered-${this.id}`, () => {
super.attach(element);
resolve();
});
});
}
/**
or it is being removed from the form.
*/
detach() {
if (this.refsreact-${this.id}
) {
this.detachReact();
}
super.detach();
}
/**
Callback passed to our React root (via the wrapper's useEffect) that will signal that React has finished rendering.
*/
onReactRendered = () => {
// verify that our Form.io-specific reference attribute is present
this.loadRefs(
this.element,
{
input: 'multiple',
},
'data-formioref',
);
if (
!this.refs['input'] ||
(Array.isArray(this.refs['input']) &&
this.refs['input'].length === 0)
) {
console.warn(
"Can't find an associated input element. Has React finished rendering? Does your input element have a formio-specific ref attribute?",
);
return;
}
this.reactRendered = true;
this.emit(react-rendered-${this.id}
, {});
};
/**
*/ attachReact(element: HTMLElement) { console.log('attaching react...'); if (!this.reactRoot) { this.reactRoot = createRoot(element); } this.reactRoot.render( <TextFieldWrapper onRendered={this.onReactRendered.bind(this)} onChange={(event) => { this.setValue(event.target.value); }} variant={'filled'} fullWidth label={this.component.label} inputProps={{ 'data-formioref': 'input' }} />, ); }
detachReact() { console.log('detaching react...'); if (this.element && this.reactRoot) { this.reactRoot.unmount(); } }
/**
react-rendered-${this.id}
, () => {
super.setValue(value, { modified: true });
});
return false;
}
super.setValue(value, { modifed: true });
return true;
}
}
Hi,
I have a React18 project and wanted to make custom react-formio component (code below) but
this.container.unmount
indetachReact
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:
Environment