diff --git a/blocks/components/editable/index.js b/blocks/components/editable/index.js index 91aec065bfa2cb..58e84cee77a46f 100644 --- a/blocks/components/editable/index.js +++ b/blocks/components/editable/index.js @@ -252,24 +252,11 @@ export default class Editable extends wp.element.Component { } } - componentWillUpdate( nextProps ) { - if ( this.editor && this.props.tagName !== nextProps.tagName ) { - this.editor.destroy(); - } - } - componentWillUnmount() { - if ( this.editor ) { - this.onChange(); - this.editor.destroy(); - } + this.onChange(); } componentDidUpdate( prevProps ) { - if ( this.props.tagName !== prevProps.tagName ) { - this.initialize(); - } - if ( !! this.props.focus && ! prevProps.focus ) { this.focus(); } @@ -339,6 +326,11 @@ export default class Editable extends wp.element.Component { const { tagName, style, value, focus, className, showAlignments = false, formattingControls } = this.props; const classes = classnames( 'blocks-editable', className ); + // Generating a key that includes `tagName` ensures that if the tag + // changes, we unmount (+ destroy) the previous TinyMCE element, then + // mount (+ initialize) a new child element in its place. + const key = [ 'editor', tagName ].join(); + let element = ( + key={ key } /> ); if ( focus ) { diff --git a/blocks/components/editable/tinymce.js b/blocks/components/editable/tinymce.js index b20039428cb04a..30d17227613ba1 100644 --- a/blocks/components/editable/tinymce.js +++ b/blocks/components/editable/tinymce.js @@ -1,5 +1,26 @@ export default class TinyMCE extends wp.element.Component { componentDidMount() { + this.initialize(); + } + + shouldComponentUpdate() { + // We must prevent rerenders because TinyMCE will modify the DOM, thus + // breaking React's ability to reconcile changes. + // + // See: https://github.com/facebook/react/issues/6802 + return false; + } + + componentWillUnmount() { + if ( ! this.editor ) { + return; + } + + this.editor.destroy(); + delete this.editor; + } + + initialize() { tinymce.init( { target: this.editorNode, theme: false, @@ -8,7 +29,10 @@ export default class TinyMCE extends wp.element.Component { browser_spellcheck: true, entity_encoding: 'raw', convert_urls: false, - setup: this.props.onSetup, + setup: ( editor ) => { + this.editor = editor; + this.props.onSetup( editor ); + }, formats: { strikethrough: { inline: 'del' } } @@ -19,14 +43,6 @@ export default class TinyMCE extends wp.element.Component { } } - shouldComponentUpdate() { - // We must prevent rerenders because TinyMCE will modify the DOM, thus - // breaking React's ability to reconcile changes. - // - // See: https://github.com/facebook/react/issues/6802 - return false; - } - render() { const { tagName = 'div', style, className, defaultValue } = this.props;