slate: Delayed setState(value) results in Cannot resolve a DOM point from Slate point
Do you want to request a feature or report a bug?
What’s the current behavior?
Repro: https://codesandbox.io/s/slate-reproductions-1sbiz
Slate: 0.57.1 Browser: Chrome OS: Mac
What’s the expected behavior?
The above repro shows how a delayed setState(value)
call systematically results in the error Cannot resolve a DOM point from Slate point
.
In my case, I’m using Apollo to keep some text in sync with the server, I have optimistic updates in place, but it’s still not quick enough to not trigger this error.
I also encountered the same issue while trying to sync with some quite large (and badly written) Redux store.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 10
- Comments: 28 (4 by maintainers)
Commits related to this issue
- Don't throw error on invalid selections, makes collaboration very hard Track issue: https://github.com/ianstormtaylor/slate/issues/3575 — committed to skogsmaskin/slate by skogsmaskin 4 years ago
- [slate-react] Don't throw error on invalid selections, with collaboration this is a problem Track issue: https://github.com/ianstormtaylor/slate/issues/3575 — committed to skogsmaskin/slate by skogsmaskin 4 years ago
- [slate-react] Don't throw error on invalid DOM selections In a collaboration session this would happen all the time. Find some way of dealing properly with this. Track issue: https://github.com/ian... — committed to skogsmaskin/slate by skogsmaskin 4 years ago
- [slate-react] Don't throw error on invalid DOM selections In a collaboration session this would happen all the time. Find some way of dealing properly with this. Track issue: https://github.com/ian... — committed to skogsmaskin/slate by skogsmaskin 4 years ago
- [slate-react] Don't throw error on invalid DOM selections In a collaboration session this would happen all the time. Find some way of dealing properly with this. Track issue: https://github.com/ian... — committed to skogsmaskin/slate by skogsmaskin 4 years ago
This is a problem when doing collaborative editing. Say user A has focus on line 2. User B removes the line above (line 1). As far as I can tell there is no way I can adjust the selection for user A before
editable
(https://github.com/ianstormtaylor/slate/blob/master/packages/slate-react/src/components/editable.tsx#L162) inslate-react
tries to update the selection itself and fails because now line 2 no longer exists.So far I have forked slate-react and just fail silently, and then adjust the selection myself.
It’s still needed to read the editor contents, but yes
value
should only be provided on startup. If we could make it readonly, we would.Modifications to
value
must be done via Slate APIs - and only via the APIs - I’m not sure where our documentation falls over trying to explain this but clearly it does.Hi guys.
I’m pretty new with Slate (a few weeks), but the current behavior looks reasonable for me. I’d be grateful if you can explain what’s wrong with it.
So, how I see it:
editor.children
contains value whileeditor.selection
contains the current state of selectioneditor.children
is exposed outside viavalue
andonChange
<Editor>
props and not updated by slate itselfeditor.selection
is purely internal stuff, which is clear as the selection can be made over a couple of nodes.Would be great to hear which of the points above aren’t correct and why.
Same issue here with remote updates as @skogsmaskin & @gabriel-peracio described, as current workaround I’m removing selection during the remote update (collaboration mode or history updates), and set it back once value updated:
In this example it’s expected that focus will be moved to the end of the string even if update happens somewhere in between (I think that this ux is better in the case if you have batching logic for remote updates), but in case if you want to keep last selection position, just store it (i.e. the ref object) and check in second hook that this selection valid for current range and set after.
But in general I think this issue should be fixed in the slate itself.
Slate core has a couple of ways to deal with this:
editor.children
) and selection (editor.selection
) are simple properties and can be changed at the same time.Ref
instances).So perhaps the React editor should expose the ability to include selection in the state, as the core does, but I also wonder if we need some documentation around getting started with collaboration. The Slate design goal is (as far as I can tell) to synchronise based on operations, not state, for the best user experience.
I have the same problem described by @skogsmaskin. My application already has collaboration built-in, which powers other widgets (slate is just one of them). I am opting out of slate’s collaborative handling and instead piggybacking on my own app’s infrastructure to make things more uniform
This error bites me constantly - when collaborating and also when using undo/redo (which, again, works through my own app code for consistency rather than using slate’s system).
User types paragraph A, then types paragraph B, then clicks
undo
. Paragraph A no longer exists, the selection is invalid, slate crashes.I also cannot store/reset the selection as part of the undo/redo mechanism, unless I use slate’s system.
As far as I can tell, the
value
prop is really only meant to be used as an initial value. When applying a differentvalue
prop (one that was not returned fromonChange
) later on this can cause all kinds of problems becauseeditor.selection
, and the history stack fromslate-history
(if you use that) can still contain values related to the old slate value. Perhaps it’s a good idea to rename thevalue
prop toinitialValue
instead?Might also need to rework the slate provider code in https://github.com/ianstormtaylor/slate/blob/main/packages/slate-react/src/components/slate.tsx a bit so it actually directly handles a re-render instead of doing this through the parent component (changing the
value
causeskey
to change which will cause a rerender).But in collaboration when I pass new value from database, It causes issues with the selection, Is there a workaround for that?
It sounded like @czechdave was requesting a reproduction case that we would expect to behave more or less synchronously. I wonder if this would serve: https://codesandbox.io/s/condescending-surf-rzcin.
It’s essentially the boilerplate from the React docs, except that it stores editor state in a Recoil atom. While Slate works as expected with editor state managed by React’s
useState
hook, moving the editor value to Recoil’suseRecoilState
hook crashes with “Cannot resolve DOM point from Slate point.”Recoil is new and a little funky, but its updates normally happen in the same lifecycle as
useState
. It would be reasonable to expect its behavior to be synchronous-ish.An option to silently fail, and maybe fallback to the closest valid position would probably a great idea