-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Post Editor: Update EmbedView to use createRef instead of string refs #39316
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,9 @@ | ||
/* eslint-disable react/no-string-refs */ | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
|
||
import ReactDom from 'react-dom'; | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React, { Component, createRef } from 'react'; | ||
import { pick } from 'lodash'; | ||
import { connect } from 'react-redux'; | ||
|
||
|
@@ -19,25 +16,12 @@ import QueryEmbed from 'components/data/query-embed'; | |
import ResizableIframe from 'components/resizable-iframe'; | ||
|
||
class EmbedView extends Component { | ||
state = { | ||
wrapper: null, | ||
}; | ||
view = createRef(); | ||
|
||
iframe = createRef(); | ||
|
||
componentDidMount() { | ||
// Rendering the frame follows a specific set of steps, whereby an | ||
// initial rendering pass is made, at which time the frame is rendered | ||
// in a second pass, before finally setting the frame markup. | ||
// | ||
// TODO: Investigate and evaluate whether we need to avoid rendering | ||
// the iframe on the initial render pass | ||
// eslint-disable-next-line react/no-did-mount-set-state | ||
this.setState( | ||
{ | ||
// eslint-disable-line react/no-did-mount-set-state | ||
wrapper: this.refs.view, | ||
}, | ||
this.setHtml | ||
); | ||
this.setHtml(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Previously, there was a But now, when this |
||
} | ||
|
||
componentDidUpdate( prevProps ) { | ||
|
@@ -49,12 +33,12 @@ class EmbedView extends Component { | |
} | ||
|
||
constrainEmbedDimensions() { | ||
if ( ! this.refs.iframe ) { | ||
if ( ! this.iframe ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return; | ||
} | ||
|
||
const view = ReactDom.findDOMNode( this.refs.view ); | ||
const iframe = ReactDom.findDOMNode( this.refs.iframe ); | ||
const view = this.view.current; | ||
const iframe = ReactDom.findDOMNode( this.iframe.current ); | ||
if ( ! iframe.contentDocument ) { | ||
return; | ||
} | ||
|
@@ -78,11 +62,11 @@ class EmbedView extends Component { | |
} | ||
|
||
setHtml() { | ||
if ( ! this.props.embed?.body || ! this.refs.iframe ) { | ||
if ( ! this.props.embed?.body || ! this.iframe ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check for |
||
return; | ||
} | ||
|
||
const iframe = ReactDom.findDOMNode( this.refs.iframe ); | ||
const iframe = ReactDom.findDOMNode( this.iframe.current ); | ||
if ( ! iframe.contentDocument ) { | ||
return; | ||
} | ||
|
@@ -98,13 +82,13 @@ class EmbedView extends Component { | |
} | ||
|
||
renderFrame() { | ||
if ( ! this.state.wrapper || ! this.props.embed ) { | ||
if ( ! this.props.embed ) { | ||
return; | ||
} | ||
|
||
return ( | ||
<ResizableIframe | ||
ref="iframe" | ||
ref={ this.iframe } | ||
onResize={ this.props.onResize } | ||
frameBorder="0" | ||
seamless | ||
|
@@ -118,7 +102,7 @@ class EmbedView extends Component { | |
|
||
return ( | ||
// eslint-disable-next-line wpcalypso/jsx-classname-namespace | ||
<div ref="view" className="wpview-content wpview-type-embed"> | ||
<div ref={ this.view } className="wpview-content wpview-type-embed"> | ||
<QueryEmbed siteId={ siteId } url={ content } /> | ||
|
||
{ this.renderFrame() } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid this
setState()
call, which forces a two pass render, might be necessary. It first renders the container<div>
and then, in second pass, creates the<iframe>
. Instead of rendering<div><iframe></div>
in one pass.When
iframe
is being created in DOM, it might go through some weird intermediate state whereiframe.contentDocument
oriframe.contentWindow
are null. And they are initialized only a moment later, when some async process inside the browser finishes.If
iframe.contentDocument
isnull
, our code can either crash, or fail to set the content HTML.I've been debugging this a few months ago inside the
components/web-preview
component and still don't understand it.Here's the relevant definition from the spec: https://html.spec.whatwg.org/multipage/iframe-embed-object.html#dom-iframe-contentwindow
I don't know what "nested browsing context" means and when it exists or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure either 🤷 I prefer closing this one to avoid introducing subtle bugs. Let's revisit in the future 👍