Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Editable tagName changes after #635 #661

Merged
merged 5 commits into from
May 4, 2017
Merged

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented May 4, 2017

I seems like we do need updating after a tag change.

@ellatrix ellatrix requested a review from aduth May 4, 2017 13:34
@ellatrix
Copy link
Member Author

ellatrix commented May 4, 2017

Going to move destroying there as well.

@mtias mtias added [Feature] Block API API that allows to express the block paradigm. TinyMCE labels May 4, 2017
@@ -1,5 +1,5 @@
export default class TinyMCE extends wp.element.Component {
componentDidMount() {
initialize() {
Copy link
Member

@aduth aduth May 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, we might want to consider conventions for component method ordering. I usually like to see:

  • Static properties
  • Constructor
  • Lifecycle methods
  • Miscellaneous
  • Render

(Considering this as "miscellaneous")

// 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;
return nextProps.tagName !== this.props.tagName;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised to find that this doesn't really break. I think it'd be worth updating the preceding comment to describe when and why we allow a rerender, and ideally how it's exempt from the concern noted in the referenced issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this sound okay?

// If the tag changes, React can reconcile the node in place after the
// editor is destroyed.

}

if ( nextProps.tagName !== this.props.tagName ) {
this.editor.destroy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this how React is able to reconcile? That we're unmounting the node altogether and React recreates it in the next pass?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The node and contents will still be there. Is that was you mean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The node and contents will still be there. Is that was you mean?

It's what I was curious about, yes, but opposite of the assumption I was making. In #635 I'd encountered issues where React would reconcile based on the DOM that TinyMCE had since modified, resulting in an infinite loop of errors, particularly around splitting and merging blocks. With these changes I'm not seeing this issue, but I don't feel confident in knowing why it's not a problem.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I'm not sure why it was a problem.

}

componentWillUnmount() {
if ( ! this.editor ) {
Copy link
Member

@aduth aduth May 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dunno if it's worth the abstraction, but I could see value in a destroy method which handles (a) verifying editor instance property, (b) destroying editor instance, (c) unsetting instance property:

destroy() {
	if ( this.editor ) {
		this.editor.destroy();
		delete this.editor;
	}
}

To the point of delete vs = null;, I don't feel strongly one way or the other, but I think in cases where we assign any instance property, it would be a good idea to initialize it to its default value in constructor so that it's clearer which instance properties exist in a class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you're right, this is cleaner.

@ellatrix ellatrix force-pushed the fix/heading-levels branch from c80566e to 69e5bb7 Compare May 4, 2017 14:12
@aduth
Copy link
Member

aduth commented May 4, 2017

In d7165a5 I pushed another approach which abuses key to render a brand new element child when tagName changes. Specifically this change:

-				key="editor" />
+				key={ [ 'editor', tagName ].join() } />

This has the same effect; namely that when tagName changes, the previous TinyMCE component will unmount, destroying the TinyMCE instance, and a new element will take it's place and reinitialize with the new tagName and content.

@ellatrix
Copy link
Member Author

ellatrix commented May 4, 2017

I'm fine with either approach :)

@aduth
Copy link
Member

aduth commented May 4, 2017

I'm fine with either approach :)

I was led to this because I'm still skeptical that React is really able to reconcile after destroying the TinyMCE instance, and that we just haven't hit the conditions where it fails hard.

@ellatrix
Copy link
Member Author

ellatrix commented May 4, 2017

Yeah, we don't take any advantage of the reconciliation otherwise, so it sounds good to not do it at all.

@ellatrix
Copy link
Member Author

ellatrix commented May 4, 2017

Looks good to me! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants