Skip to content

Commit

Permalink
Version Packages (#5290)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
2 people authored and clauderic committed Feb 22, 2023
1 parent 942fbd7 commit b6dd630
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/text-leaf-memoization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'slate-react': patch
---

Use memoization to avoid unnecessary `textContent` updates in `<TextString>` component.
24 changes: 12 additions & 12 deletions packages/slate-react/src/components/string.tsx
Original file line number Diff line number Diff line change
@@ -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 { ReactEditor, useSlateStatic } from '..'
Expand Down Expand Up @@ -61,12 +61,11 @@ const String = (props: {
*/
const TextString = (props: { text: string; isTrailing?: boolean }) => {
const { text, isTrailing = false } = props

const ref = useRef<HTMLSpanElement>(null)

const getTextContent = () => {
return `${text ?? ''}${isTrailing ? '\n' : ''}`
}
const [initialText] = useState(getTextContent)

// 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,
Expand All @@ -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
})

// Render text content immediately if it's the first-time render
// Ensure that text content is rendered on server-side rendering
if (!ref.current) {
// We intentionally render a memoized <span> that only receives the initial text content when the component is mounted.
// We defer to the layout effect above to update the `textContent` of the span element when needed.
return <MemoizedText ref={ref}>{initialText}</MemoizedText>
}

const MemoizedText = memo(
forwardRef<HTMLSpanElement, { children: string }>((props, ref) => {
return (
<span data-slate-string ref={ref}>
{getTextContent()}
{props.children}
</span>
)
}

// the span is intentionally same on every render in virtual DOM, actual rendering happens in the layout effect above
return <span data-slate-string ref={ref} />
}
})
)

/**
* Leaf strings without text, render as zero-width strings.
Expand Down

0 comments on commit b6dd630

Please sign in to comment.