react-page: Slate plugin freeze and high CPU usage with react 18
Describe the bug When I add a Text cell on react page editor, and I start to type at first there are no words coming up at all. Then sometimes it shows, then get stuck, the editor just freezes up. When I check the Brave browser task manager, I see that the page are using a lot of CPU (100-ish). I manage to get a recording of the Performance (snapshot using the performance tab of Chrome/Brave DevTools) that can be downloaded from this link.
From the screenshot of the performance recording itself, you can see how there are really deep calls, and repeated calls at the end. Is this normal?
To Reproduce Steps to reproduce the behavior:
- Create React Page Editor for React Admin field on NextJS
The plugin used itself are,
{
"@react-page/editor": "^4.9.0",
"@react-page/plugins-background": "^4.9.0",
"@react-page/plugins-divider": "^4.9.0",
"@react-page/plugins-html5-video": "^4.9.0",
"@react-page/plugins-image": "^4.9.0",
"@react-page/plugins-slate": "^4.9.0",
"@react-page/plugins-spacer": "^4.9.0",
"@react-page/plugins-video": "^4.9.0",
}
- Add New Text Cell
- Try to edit, and it should be freezing, and it’ll have high CPU usage
Expected behavior The editor should behave just like how it is the demonstration website, smooth.
Screenshots
Desktop (please complete the following information):
- OS: elementary OS 6.1 Jólnir
- Browser Brave
- Version 4.9.0
Additional context
Here are the full package.json
{
"name": "*******",
"version": "*.*.*",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"postinstall": "patch-package"
},
"dependencies": {
"@prisma/client": "3.13.0",
"@react-page/editor": "^4.9.0",
"@react-page/plugins-background": "^4.9.0",
"@react-page/plugins-divider": "^4.9.0",
"@react-page/plugins-html5-video": "^4.9.0",
"@react-page/plugins-image": "^4.9.0",
"@react-page/plugins-slate": "^4.9.0",
"@react-page/plugins-spacer": "^4.9.0",
"@react-page/plugins-video": "^4.9.0",
"@react-page/react-admin": "^4.9.0",
"next": "12.1.5",
"ra-data-simple-prisma": "^0.2.11",
"react": "18.1.0",
"react-admin": "^4.0.3",
"react-dom": "18.1.0",
"react-query": "^3.39.0"
},
"devDependencies": {
"@types/node": "17.0.29",
"@types/react": "18.0.8",
"@types/react-dom": "18.0.0",
"eslint": "8.14.0",
"eslint-config-next": "12.1.5",
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0",
"prisma": "^3.13.0",
"typescript": "4.6.3"
}
}
For the field editor component implemented like this,
import React from "react";
import type { EditorProps } from "@react-page/editor";
import Editor from "@react-page/editor";
import "@react-page/editor/lib/index.css";
import { Paper } from "@material-ui/core";
import { Labeled, useInput } from "react-admin";
const isEmpty = (obj: Object) => {
for (var _ in obj) return false;
return true;
};
export type RaReactPageInputProps = {
label?: string;
source: string;
style?: React.CSSProperties;
} & EditorProps;
const RaReactPageInput: React.FC<RaReactPageInputProps> = ({
label = "Content",
source,
style,
...editorProps
}) => {
const {
field: { value, onChange },
} = useInput({ source });
console.log("Value");
console.log(value);
return (
<Labeled label={label} source={source} fullWidth>
<>
<Paper
elevation={5}
style={{
overflow: "visible",
padding: 16,
marginRight: 64,
...style,
}}
>
<Editor
value={isEmpty(value) ? null : value}
onChange={(v) => {
console.log("On change");
console.log(v);
onChange(v);
}}
{...editorProps}
/>
</Paper>
</>
</Labeled>
);
};
export default RaReactPageInput;
And the complete cellPlugin file
import type { CellPlugin } from "@react-page/editor";
// The background plugin
import background, { ModeEnum } from "@react-page/plugins-background";
// import css as well. currently, we caannot do this here in the demo project and have moved that to _app.tsx
// see https://github.com/vercel/next.js/issues/19717
import "@react-page/plugins-background/lib/index.css";
// The divider plugin
import divider from "@react-page/plugins-divider";
// The html5-video plugin
import html5video from "@react-page/plugins-html5-video";
import "@react-page/plugins-html5-video/lib/index.css";
// The image plugin
import type { ImageUploadType } from "@react-page/plugins-image";
import { imagePlugin } from "@react-page/plugins-image";
import "@react-page/plugins-image/lib/index.css";
// The spacer plugin
import spacer from "@react-page/plugins-spacer";
import "@react-page/plugins-spacer/lib/index.css";
// The video plugin
import video from "@react-page/plugins-video";
import "@react-page/plugins-video/lib/index.css";
import slate from "@react-page/plugins-slate";
import "@react-page/plugins-slate/lib/index.css";
const fakeImageUploadService: (url: string) => ImageUploadType =
(defaultUrl) => (file, reportProgress) => {
return new Promise((resolve, reject) => {
let counter = 0;
const interval = setInterval(() => {
counter++;
reportProgress(counter * 10);
if (counter > 9) {
clearInterval(interval);
alert(
"Image has not actually been uploaded to a server. Check documentation for information on how to provide your own upload function."
);
resolve({ url: URL.createObjectURL(file) });
}
}, 100);
});
};
// Define which plugins we want to use.
export const cellPlugins: CellPlugin[] = [
// @ts-expect-error
slate((def) => ({
...def,
id: "cms-jtk-slate",
plugins: {
headings: def.plugins.headings,
alignment: def.plugins.alignment,
emphasize: def.plugins.emphasize,
paragraphs: def.plugins.paragraphs,
lists: def.plugins.lists,
link: def.plugins.link,
},
})),
// @ts-expect-error
spacer,
// @ts-expect-error
imagePlugin({ imageUpload: fakeImageUploadService("/images/react.png") }),
// @ts-expect-error
video,
divider,
// @ts-expect-error
html5video,
// @ts-expect-error
background({
imageUpload: fakeImageUploadService("/images/sea-bg.jpg"),
enabledModes:
ModeEnum.COLOR_MODE_FLAG |
ModeEnum.IMAGE_MODE_FLAG |
ModeEnum.GRADIENT_MODE_FLAG,
}),
];
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 2
- Comments: 15 (1 by maintainers)
I have provided the pull request with the workaround. It works fine under React 18 but I had to disable some features (described in this PR). I believe the indicated features pinpoint the source of the problem. Any comments and hints on how to recover them would be appreciated.