1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-16 12:14:14 +02:00

fix change queueing in <Editor> (#1196)

This commit is contained in:
Ian Storm Taylor
2017-09-29 11:12:13 -07:00
committed by GitHub
parent fbefe18110
commit ed77bf0fa1

View File

@@ -109,8 +109,8 @@ class Editor extends React.Component {
constructor(props) {
super(props)
this.tmp = {}
this.state = {}
this.tmp = {}
// Create a new `Stack`, omitting the `onChange` property since that has
// special significance on the editor itself.
@@ -118,10 +118,12 @@ class Editor extends React.Component {
const stack = Stack.create({ plugins })
this.state.stack = stack
// Resolve the state, running `onBeforeChange` first.
// Run `onBeforeChange` on the passed-in state because we need to ensure
// that it is normalized, and queue the resulting change.
const change = props.state.change()
stack.onBeforeChange(change, this)
const { state } = change
this.queueChange(change)
this.cacheState(state)
this.state.state = state
@@ -164,17 +166,34 @@ class Editor extends React.Component {
this.setState({ stack })
}
// Resolve the state, running the `onBeforeChange` handler of the stack.
// Run `onBeforeChange` on the passed-in state because we need to ensure
// that it is normalized, and queue the resulting change.
const change = props.state.change()
stack.onBeforeChange(change, this)
const { state } = change
this.queueChange(change)
this.cacheState(state)
this.setState({ state })
}
/**
* Cache a `state` in memory to be able to compare against it later, for
* things like `onDocumentChange`.
* When the component first mounts, flush any temporary changes.
*/
componentDidMount = () => {
this.flushChange()
}
/**
* When the component updates, flush any temporary change.
*/
componentDidUpdate = () => {
this.flushChange()
}
/**
* Cache a `state` object to be able to compare against it later.
*
* @param {State} state
*/
@@ -184,6 +203,37 @@ class Editor extends React.Component {
this.tmp.selection = state.selection
}
/**
* Queue a `change` object, to be able to flush it later. This is required for
* when a change needs to be applied to the state, but because of the React
* lifecycle we can't apply that change immediately. So we cache it here and
* later can call `this.flushChange()` to flush it.
*
* @param {Change} change
*/
queueChange = (change) => {
if (change.operations.length) {
debug('queueChange', { change })
this.tmp.change = change
}
}
/**
* Flush a temporarily stored `change` object, for when a change needed to be
* made but couldn't because of React's lifecycle.
*/
flushChange = () => {
const { change } = this.tmp
if (change) {
debug('flushChange', { change })
this.props.onChange(change)
delete this.tmp.change
}
}
/**
* Programmatically blur the editor.
*/
@@ -229,6 +279,7 @@ class Editor extends React.Component {
change = (fn) => {
const change = this.state.state.change()
fn(change)
debug('change', { change })
this.onChange(change)
}
@@ -243,15 +294,18 @@ class Editor extends React.Component {
throw new Error('As of slate@0.22.0 the `editor.onChange` method must be passed a `Change` object not a `State` object.')
}
const { onChange, onDocumentChange, onSelectionChange } = this.props
const { stack } = this.state
const { document, selection } = this.tmp
const { state } = change
if (state == this.state.state) return
stack.onBeforeChange(change, this)
stack.onChange(change, this)
const { state } = change
const { document, selection } = this.tmp
const { onChange, onDocumentChange, onSelectionChange } = this.props
if (state == this.state.state) return
debug('onChange', { change })
onChange(change)
if (onDocumentChange && state.document != document) onDocumentChange(state.document, change)
if (onSelectionChange && state.selection != selection) onSelectionChange(state.selection, change)