mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-12 02:03:59 +02:00
fix: remove memory leaks in Text and Editable (#5297)
* fix: remove memory leaks in Text and Editable * Add change set
This commit is contained in:
5
.changeset/grumpy-pianos-sit.md
Normal file
5
.changeset/grumpy-pianos-sit.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'slate-react': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix memory leaks by adding clean-up code that looks for ref resets in Editable and Text.
|
@@ -147,7 +147,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
const editor = useSlate()
|
const editor = useSlate()
|
||||||
// Rerender editor when composition status changed
|
// Rerender editor when composition status changed
|
||||||
const [isComposing, setIsComposing] = useState(false)
|
const [isComposing, setIsComposing] = useState(false)
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement | null>(null)
|
||||||
const deferredOperations = useRef<DeferredOperation[]>([])
|
const deferredOperations = useRef<DeferredOperation[]>([])
|
||||||
|
|
||||||
const { onUserInput, receivedUserInput } = useTrackUserInput()
|
const { onUserInput, receivedUserInput } = useTrackUserInput()
|
||||||
@@ -698,6 +698,23 @@ export const Editable = (props: EditableProps) => {
|
|||||||
[readOnly, propsOnDOMBeforeInput]
|
[readOnly, propsOnDOMBeforeInput]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const callbackRef = useCallback(
|
||||||
|
node => {
|
||||||
|
if (node == null) {
|
||||||
|
EDITOR_TO_ELEMENT.delete(editor)
|
||||||
|
NODE_TO_ELEMENT.delete(editor)
|
||||||
|
|
||||||
|
if (HAS_BEFORE_INPUT_SUPPORT) {
|
||||||
|
// @ts-ignore The `beforeinput` event isn't recognized.
|
||||||
|
ref.current.removeEventListener('beforeinput', onDOMBeforeInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.current = node
|
||||||
|
},
|
||||||
|
[ref, onDOMBeforeInput]
|
||||||
|
)
|
||||||
|
|
||||||
// Attach a native DOM event handler for `beforeinput` events, because React's
|
// Attach a native DOM event handler for `beforeinput` events, because React's
|
||||||
// built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose
|
// built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose
|
||||||
// real `beforeinput` events sadly... (2019/11/04)
|
// real `beforeinput` events sadly... (2019/11/04)
|
||||||
@@ -845,7 +862,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
// this magic zIndex="-1" will fix it
|
// this magic zIndex="-1" will fix it
|
||||||
zindex={-1}
|
zindex={-1}
|
||||||
suppressContentEditableWarning
|
suppressContentEditableWarning
|
||||||
ref={ref}
|
ref={callbackRef}
|
||||||
style={{
|
style={{
|
||||||
...(disableDefaultStyles
|
...(disableDefaultStyles
|
||||||
? {}
|
? {}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef } from 'react'
|
import React, { useRef, useCallback } from 'react'
|
||||||
import { Element, Range, Text as SlateText } from 'slate'
|
import { Element, Range, Text as SlateText } from 'slate'
|
||||||
import { ReactEditor, useSlateStatic } from '..'
|
import { ReactEditor, useSlateStatic } from '..'
|
||||||
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'
|
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'
|
||||||
@@ -32,7 +32,7 @@ const Text = (props: {
|
|||||||
text,
|
text,
|
||||||
} = props
|
} = props
|
||||||
const editor = useSlateStatic()
|
const editor = useSlateStatic()
|
||||||
const ref = useRef<HTMLSpanElement>(null)
|
const ref = useRef<HTMLSpanElement | null>(null)
|
||||||
const leaves = SlateText.decorations(text, decorations)
|
const leaves = SlateText.decorations(text, decorations)
|
||||||
const key = ReactEditor.findKey(editor, text)
|
const key = ReactEditor.findKey(editor, text)
|
||||||
const children = []
|
const children = []
|
||||||
@@ -54,20 +54,26 @@ const Text = (props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update element-related weak maps with the DOM element ref.
|
// Update element-related weak maps with the DOM element ref.
|
||||||
useIsomorphicLayoutEffect(() => {
|
const callbackRef = useCallback(
|
||||||
const KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor)
|
(span: HTMLSpanElement | null) => {
|
||||||
if (ref.current) {
|
const KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor)
|
||||||
KEY_TO_ELEMENT?.set(key, ref.current)
|
if (span) {
|
||||||
NODE_TO_ELEMENT.set(text, ref.current)
|
KEY_TO_ELEMENT?.set(key, span)
|
||||||
ELEMENT_TO_NODE.set(ref.current, text)
|
NODE_TO_ELEMENT.set(text, span)
|
||||||
} else {
|
ELEMENT_TO_NODE.set(span, text)
|
||||||
KEY_TO_ELEMENT?.delete(key)
|
} else {
|
||||||
NODE_TO_ELEMENT.delete(text)
|
KEY_TO_ELEMENT?.delete(key)
|
||||||
}
|
NODE_TO_ELEMENT.delete(text)
|
||||||
})
|
if (ref.current) {
|
||||||
|
ELEMENT_TO_NODE.delete(ref.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref.current = span
|
||||||
|
},
|
||||||
|
[ref, editor, key, text]
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<span data-slate-node="text" ref={ref}>
|
<span data-slate-node="text" ref={callbackRef}>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user