Copy pasting (really) large text no longer seems to work?
See original GitHub issueDo you want to request a feature or report a bug?
A bug, I’ve also mentioned it in the slack channel
What’s the current behavior?
If you take the plain text of a book, eg Moby Dick from Gutemberg’s books and you copy paste it in SlateJs(plain text demo) It freezes the UI.
Slate: 0.XX.X // Whatever slateJs version you have on slatejs.org? Browser: Tried on Brave/ Chrome / Safari / Firefox OS: Mac
What’s the expected behavior?
For the UI not to freeze when pasting large body of text.
It used to work a while ago, when I had tried this before, that the UI did not freeze, and it was surprisingly quite performant at handling such a large document, eg if you tried to delete a paragraph, there was very little lag.
You can try to do the same thing in draftJs and you’ll see, you’ll be able to copy/paste the whole text. And that if you delete a paragraph there’s a few seconds delay before the changes takes effect.
sandbox 1
Since you ask for sandbox env to reproduce, I splitted the books line into draft paragraphs, and added it to a sandbox - altho that is not quite the sam as reproducing the bug describe above.
const text = `//string containing moby dick book from gutemberg's books plain text link
const slateData = text.trim().split('\n').map((line)=>{
return {
text: line,
marks: []
}
})
// slateData is what I've added to the code sandbox.
https://codesandbox.io/s/slate-reproductions-forked-4j5r9
As you can see in the gif below it takes a few seconds to delete some text. If I recall correctly that did not used to be the case when I tried the same thing in earlier versions.
sandbox 2
I also realized the example above was putting all the text into one paragraph so tried as separate paragraphs
const text = `//string containing moby dick book from gutemberg's books plain text link
const slateData = text.trim().split('\n').map((line)=>{
return {
children: [{
text: line,
marks: []
}]}
})
https://codesandbox.io/s/slate-reproductions-forked-5inqx
That’s a bit better still a little lag
Let me know if there’s anything else I can do to help figure this out.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:8
@piotrkubisa remarked:
I’m also building an editor around Slate.js (because slatejs has the best API and philosophy of any WYSIWIG editor builder I’ve ever seen, by far!), but the issues with scalability mean that I also can’t use slate-react exactly as is. Lately I’ve been tearing apart slate-react to better understand why some things are slow.
One interesting oddity in the code relevant to this discussion is in
slate/packages/slate-react/src/components/text.tsx
, which has this function:In a situation where there are say 5000 Text sibling children nodes, if you change exactly one of them, then the comparison
next.parent === prev.parent
will be false for all 5000 of them. This is because all 5000 children text nodes have the same parent, and that parent changed (because the parent has the children array as an attribute, and one element of that array changed). This is why you observe:It’s not just that it goes through that loop you mentioned (which is mildly annoying), it’s also that every single child is also definitely re-rendered because MemoizedText can never ever work in this setting.
I’m not 100% sure how to fix MemoizedText properly yet; in my personal fork I’m just commenting out
next.parent === prev.parent &&
and seeing a very significant performance improvement. Note that inslate/packages/slate-react/src/components/element.tsx
there is a very similar MemoizedElement, and it does not include the parent in its comparison function.I implemented a quick proof of concept of this today using the latest slate-react, and looking at #2627. What I wrote is I think pretty close to #2627 (though I think that was patches against a version different version of slate). It’s not possible for me to do this as a plugin as far as I can tell; you really have to just rewrite bits of slate-react (which is of course a plugin so technically what I’m saying is false). Using react-windowed (tested on a bunch of big documents) works incredibly well for long documents, where editor.children.length is large. I’m mainly using slatejs to implement markdown editing and a new Jupyter notebook client, so large editor.children.length is exactly my use case, and my users often make really long documents (with 500+ top level elements). The drawback to windowing, as explained at #2627, is that using react-window means that you suddenly get a new todo list of nontrivial tasks (selection beyond the window size definitely breaks right without significant work, ctrl+f to find is of course broken, subtle issues if the selection contains something that gets removed from the DOM, etc.). I expect it will be pretty hard to rewrite slate-react to do all that, but I don’t really see any choice (I would love to be wrong!).
None of this code I wrote is stable or usable, but I just thought somebody might find this little report on what I’m finding of interest. I’m pushing my code to the branch associated to this PR (see src/smc-webapp/frame-editors/markdown-editor/slate/slate-react/ in there) in case anybody wants to look at code.
I found possibly correlated issue that I have noticed and tried to raise a discussion about it on slate’s Slack… but I failed 😦
I was trying with other text (https://orgmode.org/worg/dev/org-syntax.org.html), which I find more contemporary example for an editor. When I paste it 2x or 3x into any kind of Slate editor, the lag to type
Hello World
is barely to withstand. I really wish to useslate
but definitely many users will notice that problem and they might be very not satisfied with the editor.The
slate-react
is simplified:Every time any event fires the
<Children />
is going to be updated, which not surprising, but the problem it causes hit a loop there https://github.com/ianstormtaylor/slate/blob/dd351c9d0aca2599f9375e707361feff370996bb/packages/slate-react/src/components/children.tsx#L39-L82Aforementioned loop is also triggered every time you change cursor or type any character, not saying about the paste operation (AFAIK it will be called that many times how many lines you have).
It is completely tragic in the result, comparing it to the
Zoho Writer
(it has own editor canvas, jQuery-based, they use a absolute- positionable<span contentEditable={true}> </span>
block as a cursor),TipTap
(Vue.js),Remirror
(ProseMirror in React.js) but similar toQuill.js
.There is an also attempt to implement
slate
in Vue (https://github.com/marsprince/slate-vue) and the result is notably better in terms of responsivity after the pasting operation - I can write some text easily, which is unlikely inslate-react
. What I have noticed is that only specific editor operations causes to call re-render on all tree.Going back to the problem. Do you have any suggestion to improve the responsivity? Virtualizing the rendering? It was discussed earlier (https://github.com/ianstormtaylor/slate/pull/2627) and likely it is not going be the eyed solution. More aggressive caching? Any ideas?