bangle-editor
bangle-editor copied to clipboard
React Strict Mode: Error: It looks like renderHandlers were already set by someone else.
The editor crashes with React 18 in development only, with the most basic setup. When building for production it works as expected.
const editorState = useEditorState({
specRegistry: new SpecRegistry([]),
})
return (
<BangleEditor
state={editorState}
/>
)
Uncaught Error: It looks like renderHandlers were already set by someone else.
at saveRenderHandlers (index.js:774:15)
at index.js:37:9
at commitHookEffectListMount (react-dom.development.js:23150:26)
at invokePassiveEffectMountInDEV (react-dom.development.js:25154:13)
at invokeEffectsInDev (react-dom.development.js:27351:11)
at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27330:7)
at flushPassiveEffectsImpl (react-dom.development.js:27056:5)
at flushPassiveEffects (react-dom.development.js:26984:14)
at react-dom.development.js:26769:9
at workLoop (scheduler.development.js:266:34)
Using
"vite": "^3.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
UPDATE: It only crashes when <React.StrictMode> is used
EDIT: Added a link to my working example below
I do have a PR open to fix this issue, but for those of us that want to keep using React.StrictMode in the meantime I do have a workaround!
For those curious as to why this issue only occurs in StrictMode it causes react to invoke most hooks twice in order to detect potential side effects.
Workaround
Javascript being the wonderfully messed up language it is allows us to do the following.
Typescript
import { BangleEditor, useEditorState } from '@bangle.dev/react';
((has) => {
WeakMap.prototype.has = function (key: WeakKey) {
if (key instanceof HTMLDivElement && key.parentElement?.id === 'bangle-editor') return false;
return has.bind(this)(key);
};
})(WeakMap.prototype.has);
export function Editor() {
const state = useEditorState({
// ...
});
return (
<div id="bangle-editor">
<BangleEditor state={state} />
</div>
);
}
Javascript
import { BangleEditor, useEditorState } from '@bangle.dev/react';
((has) => {
WeakMap.prototype.has = function (key) {
if (key instanceof HTMLDivElement && key.parentElement?.id === 'bangle-editor') return false;
return has.bind(this)(key);
};
})(WeakMap.prototype.has);
export function Editor() {
const state = useEditorState({
// ...
});
return (
<div id="bangle-editor">
<BangleEditor state={state} />
</div>
);
}