mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-13 18:53:59 +02:00
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
5
.changeset/text-leaf-memoization.md
Normal file
5
.changeset/text-leaf-memoization.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'slate-react': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Use memoization to avoid unnecessary `textContent` updates in `<TextString>` component.
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef } from 'react'
|
import React, { forwardRef, memo, useRef, useState } from 'react'
|
||||||
import { Editor, Text, Path, Element, Node } from 'slate'
|
import { Editor, Text, Path, Element, Node } from 'slate'
|
||||||
|
|
||||||
import { ReactEditor, useSlateStatic } from '..'
|
import { ReactEditor, useSlateStatic } from '..'
|
||||||
@@ -61,12 +61,11 @@ const String = (props: {
|
|||||||
*/
|
*/
|
||||||
const TextString = (props: { text: string; isTrailing?: boolean }) => {
|
const TextString = (props: { text: string; isTrailing?: boolean }) => {
|
||||||
const { text, isTrailing = false } = props
|
const { text, isTrailing = false } = props
|
||||||
|
|
||||||
const ref = useRef<HTMLSpanElement>(null)
|
const ref = useRef<HTMLSpanElement>(null)
|
||||||
|
|
||||||
const getTextContent = () => {
|
const getTextContent = () => {
|
||||||
return `${text ?? ''}${isTrailing ? '\n' : ''}`
|
return `${text ?? ''}${isTrailing ? '\n' : ''}`
|
||||||
}
|
}
|
||||||
|
const [initialText] = useState(getTextContent)
|
||||||
|
|
||||||
// This is the actual text rendering boundary where we interface with the DOM
|
// This is the actual text rendering boundary where we interface with the DOM
|
||||||
// The text is not rendered as part of the virtual DOM, as since we handle basic character insertions natively,
|
// The text is not rendered as part of the virtual DOM, as since we handle basic character insertions natively,
|
||||||
@@ -89,19 +88,20 @@ const TextString = (props: { text: string; isTrailing?: boolean }) => {
|
|||||||
// as this effectively replaces "specifying the text in the virtual DOM under the <span> below" on each render
|
// as this effectively replaces "specifying the text in the virtual DOM under the <span> below" on each render
|
||||||
})
|
})
|
||||||
|
|
||||||
// Render text content immediately if it's the first-time render
|
// We intentionally render a memoized <span> that only receives the initial text content when the component is mounted.
|
||||||
// Ensure that text content is rendered on server-side rendering
|
// We defer to the layout effect above to update the `textContent` of the span element when needed.
|
||||||
if (!ref.current) {
|
return <MemoizedText ref={ref}>{initialText}</MemoizedText>
|
||||||
return (
|
|
||||||
<span data-slate-string ref={ref}>
|
|
||||||
{getTextContent()}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the span is intentionally same on every render in virtual DOM, actual rendering happens in the layout effect above
|
const MemoizedText = memo(
|
||||||
return <span data-slate-string ref={ref} />
|
forwardRef<HTMLSpanElement, { children: string }>((props, ref) => {
|
||||||
}
|
return (
|
||||||
|
<span data-slate-string ref={ref}>
|
||||||
|
{props.children}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leaf strings without text, render as zero-width strings.
|
* Leaf strings without text, render as zero-width strings.
|
||||||
|
Reference in New Issue
Block a user