mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-21 06:31:28 +02:00
implement isomorphic layout effect (#3262)
supresses warning on SSR when using useLayoutEffect by falling back to useEffect when window is undefined neither useLayoutEffect nor useEffect is run on server
This commit is contained in:
committed by
Ian Storm Taylor
parent
1389093f06
commit
56d798a943
@@ -1,10 +1,4 @@
|
|||||||
import React, {
|
import React, { useEffect, useRef, useMemo, useCallback } from 'react'
|
||||||
useLayoutEffect,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
useMemo,
|
|
||||||
useCallback,
|
|
||||||
} from 'react'
|
|
||||||
import { Editor, Element, NodeEntry, Node, Range, Text } from 'slate'
|
import { Editor, Element, NodeEntry, Node, Range, Text } from 'slate'
|
||||||
import debounce from 'debounce'
|
import debounce from 'debounce'
|
||||||
import scrollIntoView from 'scroll-into-view-if-needed'
|
import scrollIntoView from 'scroll-into-view-if-needed'
|
||||||
@@ -15,6 +9,7 @@ import { IS_FIREFOX, IS_SAFARI } from '../utils/environment'
|
|||||||
import { ReactEditor } from '..'
|
import { ReactEditor } from '..'
|
||||||
import { ReadOnlyContext } from '../hooks/use-read-only'
|
import { ReadOnlyContext } from '../hooks/use-read-only'
|
||||||
import { useSlate } from '../hooks/use-slate'
|
import { useSlate } from '../hooks/use-slate'
|
||||||
|
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'
|
||||||
import {
|
import {
|
||||||
DOMElement,
|
DOMElement,
|
||||||
DOMNode,
|
DOMNode,
|
||||||
@@ -106,7 +101,7 @@ export const Editable = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Update element-related weak maps with the DOM element ref.
|
// Update element-related weak maps with the DOM element ref.
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
EDITOR_TO_ELEMENT.set(editor, ref.current)
|
EDITOR_TO_ELEMENT.set(editor, ref.current)
|
||||||
NODE_TO_ELEMENT.set(editor, ref.current)
|
NODE_TO_ELEMENT.set(editor, ref.current)
|
||||||
@@ -121,7 +116,7 @@ export const Editable = (
|
|||||||
// leaky polyfill that only fires on keypresses or clicks. Instead, we want to
|
// leaky polyfill that only fires on keypresses or clicks. Instead, we want to
|
||||||
// fire for any change to the selection inside the editor. (2019/11/04)
|
// fire for any change to the selection inside the editor. (2019/11/04)
|
||||||
// https://github.com/facebook/react/issues/5785
|
// https://github.com/facebook/react/issues/5785
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
window.document.addEventListener('selectionchange', onDOMSelectionChange)
|
window.document.addEventListener('selectionchange', onDOMSelectionChange)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -136,7 +131,7 @@ export const Editable = (
|
|||||||
// 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)
|
||||||
// https://github.com/facebook/react/issues/11211
|
// https://github.com/facebook/react/issues/11211
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
// @ts-ignore The `beforeinput` event isn't recognized.
|
// @ts-ignore The `beforeinput` event isn't recognized.
|
||||||
ref.current.addEventListener('beforeinput', onDOMBeforeInput)
|
ref.current.addEventListener('beforeinput', onDOMBeforeInput)
|
||||||
@@ -151,7 +146,7 @@ export const Editable = (
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Whenever the editor updates, make sure the DOM selection state is in sync.
|
// Whenever the editor updates, make sure the DOM selection state is in sync.
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
const { selection } = editor
|
const { selection } = editor
|
||||||
const domSelection = window.getSelection()
|
const domSelection = window.getSelection()
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useLayoutEffect, useRef } from 'react'
|
import React, { useRef } from 'react'
|
||||||
import getDirection from 'direction'
|
import getDirection from 'direction'
|
||||||
import { Editor, Node, Range, NodeEntry, Element as SlateElement } from 'slate'
|
import { Editor, Node, Range, NodeEntry, Element as SlateElement } from 'slate'
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@ import Text from './text'
|
|||||||
import Children from './children'
|
import Children from './children'
|
||||||
import { ReactEditor, useEditor, useReadOnly } from '..'
|
import { ReactEditor, useEditor, useReadOnly } from '..'
|
||||||
import { SelectedContext } from '../hooks/use-selected'
|
import { SelectedContext } from '../hooks/use-selected'
|
||||||
|
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'
|
||||||
import {
|
import {
|
||||||
NODE_TO_ELEMENT,
|
NODE_TO_ELEMENT,
|
||||||
ELEMENT_TO_NODE,
|
ELEMENT_TO_NODE,
|
||||||
@@ -111,7 +112,7 @@ const Element = (props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update element-related weak maps with the DOM element ref.
|
// Update element-related weak maps with the DOM element ref.
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
KEY_TO_ELEMENT.set(key, ref.current)
|
KEY_TO_ELEMENT.set(key, ref.current)
|
||||||
NODE_TO_ELEMENT.set(element, ref.current)
|
NODE_TO_ELEMENT.set(element, ref.current)
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
import React, { useLayoutEffect, useRef } from 'react'
|
import React, { useRef } from 'react'
|
||||||
import { Range, Element, Text as SlateText } from 'slate'
|
import { Range, Element, Text as SlateText } from 'slate'
|
||||||
|
|
||||||
import Leaf from './leaf'
|
import Leaf from './leaf'
|
||||||
import { ReactEditor, useEditor } from '..'
|
import { ReactEditor, useEditor } from '..'
|
||||||
import { RenderLeafProps } from './editable'
|
import { RenderLeafProps } from './editable'
|
||||||
|
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'
|
||||||
import {
|
import {
|
||||||
KEY_TO_ELEMENT,
|
KEY_TO_ELEMENT,
|
||||||
NODE_TO_ELEMENT,
|
NODE_TO_ELEMENT,
|
||||||
@@ -44,7 +45,7 @@ const Text = (props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update element-related weak maps with the DOM element ref.
|
// Update element-related weak maps with the DOM element ref.
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
KEY_TO_ELEMENT.set(key, ref.current)
|
KEY_TO_ELEMENT.set(key, ref.current)
|
||||||
NODE_TO_ELEMENT.set(text, ref.current)
|
NODE_TO_ELEMENT.set(text, ref.current)
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
import { useLayoutEffect, useEffect } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent warning on SSR by falling back to useEffect when window is not defined
|
||||||
|
*/
|
||||||
|
export const useIsomorphicLayoutEffect =
|
||||||
|
typeof window !== 'undefined' ? useLayoutEffect : useEffect
|
Reference in New Issue
Block a user