From e036f10f17909fb36e4fe1574bab9abd9dbc67ac Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 26 Sep 2017 10:30:39 -0700 Subject: [PATCH 1/4] Update Portals Documentation Correct some grammar to be more explicit and clear. Update example CodePen to better match code found in documentation. Update code example styles to match other code examples (ie. 'State and Lifecycle', 'Handling Events'). --- docs/docs/portals.md | 49 ++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/docs/docs/portals.md b/docs/docs/portals.md index 5545fb9f2753..4272293165e6 100644 --- a/docs/docs/portals.md +++ b/docs/docs/portals.md @@ -44,47 +44,66 @@ A typical use case for portals is when a parent component has an `overflow: hidd > Note: > -> For most uses portals, you'll need to make sure to follow the proper accessibility guidelines. +> It is important to remember, when working with portals, you'll need to make sure to follow the proper accessibility guidelines. [Try out an example on CodePen.](https://codepen.io/acdlite/pen/JrKgmz) ## Portals and event bubbling -A nice feature of portals is that, even though the DOM node can be anywhere in the DOM tree, it behaves like a normal React child in every other way. Features like context work exactly the same regardless of whether the child is a portal. +Even though a portal can be anywhere in the DOM tree, it behaves like a normal React child in every other way. Features like context work exactly the same regardless of whether the child is a portal, as the portal still exists in the *React tree* regardless of position in the *DOM tree*. -This includes event bubbling: an event fired from inside a portal will propagate to ancestors in the containing *React tree*, even if those elements are not ancestors in the *DOM tree*: +This includes event bubbling. An event fired from inside a portal will propagate to ancestors in the containing *React tree*, even if those elements are not ancestors in the *DOM tree*. Assuming the following HTML structure: + +```html + + +
+ + + +``` + +A Parent component in #app-root would be able to catch an uncaught, bubbling event from the sibling node #modal-root. ```js -// These two containers are siblings in the DOM -const appContainer = document.getElementById('app-container'); -const modalContainer = document.getElementById('modal-container'); +const appRoot = document.getElementById('app-root'); +const modalRoot = document.getElementById('modal-root'); class Parent extends React.Component { - state = {clicks: 0}; + constructor(props) { + super(props); + this.state = {clicks: 0}; + } onClick = () => { - // This will fire when the button in Child is clicked, even though - // button is not direct descendant in the DOM. - this.setState(state => ({clicks: state.clicks + 1})); + // This will fire when the button in Child is clicked, updating Parent's state, + // even though button is not direct descendant in the DOM. + this.setState(prevState => ({clicks: prevState.clicks + 1})); }; render() { return (

Number of clicks: {this.state.clicks}

Open up the browser DevTools to observe that the button is not a child the div with onClick handler.

- {ReactDOM.createPortal(, modalContainer)} + {ReactDOM.createPortal(, modalRoot)}
); } } function Child() { - return ; + // The click event on this button will bubble up to parent, + // because there is no 'onClick' attribute defined + return ( + + ); } -ReactDOM.render(, appContainer); +ReactDOM.render(, appRoot); ``` -[Try this example on CodePen](https://codepen.io/acdlite/pen/MEJEVV). +[Try this example on CodePen](https://codepen.io/savepointsam/pen/gGmpKa). -The advantage of treating portal event bubbling this way is that it makes it easier to build abstractions. For example, if you render a `` component, the parent can capture its events regardless of whether it's implemented using portals. \ No newline at end of file +Catching an event bubbling up from a portal in a parent component allows the development of more flexible abstractions that are not inherently reliant on portals. For example, if you render a `` component, the parent can capture its events regardless of whether it's implemented using portals. From acaccd38be88828bda3468a4176d5d22199b7996 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 26 Sep 2017 10:45:06 -0700 Subject: [PATCH 2/4] Clean up comment to be accurate to example There was a small comment overlooked when reviewing the documentation. This fixes it to be accurate to the example as well as grammatically correct. --- docs/docs/portals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/portals.md b/docs/docs/portals.md index 4272293165e6..33945e9cf330 100644 --- a/docs/docs/portals.md +++ b/docs/docs/portals.md @@ -76,7 +76,7 @@ class Parent extends React.Component { } onClick = () => { // This will fire when the button in Child is clicked, updating Parent's state, - // even though button is not direct descendant in the DOM. + // even though Child is not a direct descendant in the DOM. this.setState(prevState => ({clicks: prevState.clicks + 1})); }; render() { From ec3acf93ea21ab24e02b01717dde398d657cf28a Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 26 Sep 2017 19:42:25 +0100 Subject: [PATCH 3/4] Update portals.md --- docs/docs/portals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/portals.md b/docs/docs/portals.md index 33945e9cf330..8166a5435424 100644 --- a/docs/docs/portals.md +++ b/docs/docs/portals.md @@ -63,7 +63,7 @@ This includes event bubbling. An event fired from inside a portal will propagate ``` -A Parent component in #app-root would be able to catch an uncaught, bubbling event from the sibling node #modal-root. +A Parent component in `#app-root` would be able to catch an uncaught, bubbling event from the sibling node #modal-root. ```js const appRoot = document.getElementById('app-root'); From b25afd4d72aa4a3c4bd1adc277e74b41a2c6acc2 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 26 Sep 2017 19:45:39 +0100 Subject: [PATCH 4/4] More fixes --- docs/docs/portals.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/docs/portals.md b/docs/docs/portals.md index 8166a5435424..a59e0422a3cc 100644 --- a/docs/docs/portals.md +++ b/docs/docs/portals.md @@ -33,7 +33,7 @@ However, sometimes it's useful to insert a child into a different location in th render() { // React does *not* create a new div. It renders the children into `domNode`. // `domNode` is any valid DOM node, regardless of its location in the DOM. - return React.createPortal( + return ReactDOM.createPortal( this.props.children, domNode, ); @@ -73,12 +73,17 @@ class Parent extends React.Component { constructor(props) { super(props); this.state = {clicks: 0}; + this.handleClick = this.handleClick.bind(this); } - onClick = () => { + + handleClick() { // This will fire when the button in Child is clicked, updating Parent's state, // even though Child is not a direct descendant in the DOM. - this.setState(prevState => ({clicks: prevState.clicks + 1})); - }; + this.setState(prevState => ({ + clicks: prevState.clicks + 1 + })); + } + render() { return (
@@ -94,7 +99,7 @@ function Child() { // The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return ( -