From 04c2b9c038cc4086f06bfb734d4cf8e88b4db5d2 Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Fri, 16 Feb 2018 15:49:55 -0800 Subject: [PATCH] Move _latestEditorState assignment back to commit phase Summary: Follow-up to D6994261. I believe this is more correct even though it is kind of a hacky approach. Reviewed By: flarnie Differential Revision: D7014753 fbshipit-source-id: 6107352ddbe5a90fa3235aae513a3c5b17574c55 --- src/component/base/DraftEditor.react.js | 96 +++++++++++++++---------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/src/component/base/DraftEditor.react.js b/src/component/base/DraftEditor.react.js index c6abc9b732..de49b2ae3e 100644 --- a/src/component/base/DraftEditor.react.js +++ b/src/component/base/DraftEditor.react.js @@ -65,6 +65,60 @@ type State = { let didInitODS = false; +class UpdateEditorState extends React.Component<{ + editor: DraftEditor, + editorState: EditorState, +}> { + render() { + return null; + } + componentDidMount() { + this._update(); + } + componentDidUpdate() { + this._update(); + } + _update() { + if (gkx('draft_js_remove_componentwillupdate')) { + /** + * Sometimes a render triggers a 'focus' or other event, and that will + * schedule a second render pass. + * In order to make sure the second render pass gets the latest editor + * state, we update it here. + * Example: + * render #1 + * + + * | + * | cWU -> Nothing ... latestEditorState = STALE_STATE :( + * | + * | render -> this.props.editorState = FRESH_STATE + * | + *and* set latestEditorState = FRESH_STATE + * | + * | | + * | +--> triggers 'focus' event, calling 'handleFocus' with latestEditorState + * | + + * | | + * +>cdU -> latestEditorState = FRESH_STATE | the 'handleFocus' call schedules render #2 + * | with latestEditorState, which is FRESH_STATE + * | + * render #2 <--------------------------------------+ + * + + * | + * | cwU -> nothing updates + * | + * | render -> this.props.editorState = FRESH_STATE which was passed in above + * | + * +>cdU fires and resets latestEditorState = FRESH_STATE + * --- + * Note that if we don't set latestEditorState in 'render' in the above + * diagram, then STALE_STATE gets passed to render #2. + */ + const editor = this.props.editor; + editor._latestEditorState = this.props.editorState; + } + } +} + /** * `DraftEditor` is the root editor component. It composes a `contentEditable` * div, and provides a wide variety of useful function props for managing the @@ -237,43 +291,6 @@ class DraftEditor extends React.Component { } render(): React.Node { - if (gkx('draft_js_remove_componentwillupdate')) { - /** - * Sometimes a render triggers a 'focus' or other event, and that will - * schedule a second render pass. - * In order to make sure the second render pass gets the latest editor - * state, we update it here. - * Example: - * render #1 - * + - * | - * | cWU -> Nothing ... latestEditorState = STALE_STATE :( - * | - * | render -> this.props.editorState = FRESH_STATE - * | + *and* set latestEditorState = FRESH_STATE - * | - * | | - * | +--> triggers 'focus' event, calling 'handleFocus' with latestEditorState - * | + - * | | - * +>cdU -> latestEditorState = FRESH_STATE | the 'handleFocus' call schedules render #2 - * | with latestEditorState, which is FRESH_STATE - * | - * render #2 <--------------------------------------+ - * + - * | - * | cwU -> nothing updates - * | - * | render -> this.props.editorState = FRESH_STATE which was passed in above - * | - * +>cdU fires and resets latestEditorState = FRESH_STATE - * --- - * Note that if we don't set latestEditorState in 'render' in the above - * diagram, then STALE_STATE gets passed to render #2. - */ - - this._latestEditorState = this.props.editorState; - } const { blockRenderMap, blockRendererFn, @@ -381,6 +398,11 @@ class DraftEditor extends React.Component { style={contentStyle} suppressContentEditableWarning tabIndex={this.props.tabIndex}> + {/* + Needs to come earlier in the tree as a sibling (not ancestor) of + all DraftEditorLeaf nodes so it's first in postorder traversal. + */} +