Open 12joan opened 3 months ago
Regarding the issues encountered with using ReactEditor.findPath
, I also have some thoughts and solutions:
ReactEditor.findPath
as the primary method. If it fails, I will iterate over editor.children
as a fallback to ensure correct data retrieval as much as possible.<Editable />
rendering is complete within useEffect.@WindrunnerMax Those are good workarounds. I'm hoping that with the changes to ReactEditor.findPath
I describe above, those workaround won't be necessary anymore.
Problem It looks to me like the only reason
findPath
is coupled to slate-react is for performance reasons. By using slate-react’sNODE_TO_PARENT
andNODE_TO_INDEX
weak maps,ReactEditor.findPath
is able to find the path of any rendered node very efficiently, in linear time relative to the depth of the node to be found.However, this comes with some drawbacks:
Solution My proposed solution has two parts.
First, we introduce a new
Editor.findPath
method in the core Slate package, which finds the path of a node by traversing the entire tree usingEditor.nodes
until a matching node is found.Second, we improve the reliability of
ReactEditor.findPath
by having it validate the information from the weak maps against the actual editor value, and have it useEditor.findPath
as a fallback instead of throwing an error.Algorithm for
ReactEditor.findPath
:parent
andindex
forchild
from the weak mapsparent.children[index] === child
parent.children.indexOf(child)
finds a matching node. If so, replaceindex
with this new index and continue. Otherwise, throw an error.index
to thepath
and setchild
equal toparent
Editor.findPath
, which will throw its own error if the node genuinely doesn't existAlternatives If we decide that the performance benefit from using the weak maps-based solution isn't worth the drawbacks or added compexity to work around those drawbacks, we could remove it entirely and replace it with the traversal-based solution.
However, I think the performance benefit from using weak maps is justified. I've seen many apps call
ReactEditor.findPath
at the top level of a React component (although admittedly this is something I tend to discourage). In an app where all nodes do this, using a traversal-based solution by default would increase the complexity of rendering all nodes from O(N) to O(N^2), where N is the number of nodes in the editor.I think using weak maps by default but using traversal as a fallback is the best solution.
Context In Plate, we’re trying to decouple our plugins from React. We’ve found that the dependency of the
findPath
function on slate-react is an obstacle to this.We're also considering adding an
editor.findPath
method that defaults toEditor.findPath
but whichwithReact
automatically replaces withReactEditor.findPath
. The issue with this is that the pattern established in #5307 has methods inEditor
depending oneditor
, not the other way around. For that reason, I think we'll probably do this in Plate only rather than in Slate.