Skip to content

Commit 55d113a

Browse files
authored
Merge pull request #14 from WTW-IM/react-17
React 17 Implementation
2 parents 6ab64a3 + 9c61c45 commit 55d113a

File tree

8 files changed

+5793
-3386
lines changed

8 files changed

+5793
-3386
lines changed

CHANGELOG.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
# [3.0.0-react-17.3](https://github.com/WTW-IM/react-html-element/compare/v3.0.0-react-17.2...v3.0.0-react-17.3) (2021-02-05)
2+
3+
4+
### Docs
5+
6+
* completing React 17 docs ([1d48bc0](https://github.com/WTW-IM/react-html-element/commit/1d48bc0e31df2fa50de84fd930779c6c69cb8006))
7+
* fixing react-16 link ([43435a4](https://github.com/WTW-IM/react-html-element/commit/43435a4ccc425433afabaefd577aff633e0accff))
8+
9+
# [3.0.0-react-17.2](https://github.com/WTW-IM/react-html-element/compare/v3.0.0-react-17.1...v3.0.0-react-17.2) (2021-02-04)
10+
11+
12+
### Docs
13+
14+
* describing why this is useful with React 17 ([c12ca21](https://github.com/WTW-IM/react-html-element/commit/c12ca21c9d0cff0c8636593d15889c641034205a))
15+
16+
### Fix
17+
18+
* ensuring we only load the HTML 5 Adapter when we need it ([871755f](https://github.com/WTW-IM/react-html-element/commit/871755fc4b78fc557e77bf3b7bd6048480b3a34d))
19+
20+
# [3.0.0-react-17.1](https://github.com/WTW-IM/react-html-element/compare/v2.2.0...v3.0.0-react-17.1) (2021-02-04)
21+
22+
23+
### Breaking
24+
25+
* removing event retargeting ([60abc05](https://github.com/WTW-IM/react-html-element/commit/60abc05ffed68591840c7651d0c3a49668c4d040))
26+
27+
### Build
28+
29+
* ensuring we push package.json with semantic-release commit ([f0531bc](https://github.com/WTW-IM/react-html-element/commit/f0531bca4998708fe7e37117e28a4e5ab213cf8c))
30+
* reconfiguring .travis.yml to use on conditions ([f587a7c](https://github.com/WTW-IM/react-html-element/commit/f587a7cc127ed61413c74cbcfc9f26bc7b015755))
31+
* running release build on react-16 and react-17 branches ([4abdde9](https://github.com/WTW-IM/react-html-element/commit/4abdde98d68464bd32b0f52acebee9701dde6815))
32+
* setting up release for react-17 ([9d9d4ad](https://github.com/WTW-IM/react-html-element/commit/9d9d4add5f77e7b6089195a357893abc1764a6fe))
33+
34+
### Update
35+
36+
* adding a base-level render function ([9cb8a6b](https://github.com/WTW-IM/react-html-element/commit/9cb8a6b5a5a66eafa827dfebe2e83577f7a70b68))
37+
* adding this.shadow for easy style placement ([1a5c275](https://github.com/WTW-IM/react-html-element/commit/1a5c2758acaf3850d67852efe61fa95899f00259))
38+
* ensuring we can accommodate lower versions of React 17 ([2cac97b](https://github.com/WTW-IM/react-html-element/commit/2cac97b4eea0305b018f87f65eca049d79520878))
39+
40+
### Upgrade
41+
42+
* updating all dependencies ([5737167](https://github.com/WTW-IM/react-html-element/commit/5737167f47ffb4b3e99fc7f15e4bd1f987663eb7))
43+
144
# [2.2.0](https://github.com/WTW-IM/react-html-element/compare/v2.1.0...v2.2.0) (2021-01-12)
245

346

README.md

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
[![Build Status](https://travis-ci.com/WTW-IM/react-html-element.svg?branch=master)](https://travis-ci.com/github/WTW-IM/react-html-element)
44
[![npm version](https://badge.fury.io/js/react-html-element.svg)](https://badge.fury.io/js/react-html-element)
55

6-
## The Problem
6+
## NOTE:
77

8-
The [React documentation around using React in Web Components](https://reactjs.org/docs/web-components.html#using-react-in-your-web-components) presents a case where you can create Web Components using React, but when explored, utilizing React in Web Components presents some significant functionality issues, as detailed in [this issue](https://github.com/facebook/react/issues/9242). Namely, complex React apps rendered in Web Components lose their functionality.
8+
This package works with React at version 17. For version 16, [see the react-16
9+
branch of this repo](https://github.com/WTW-IM/react-html-element/tree/react-16).
910

10-
## The Solution
11+
## What is it?
1112

12-
`react-html-element` seamlessly creates the glue needed to utilize React in your Web Components without losing functionality.
13+
`react-html-element` gives a few quality of life improvements over using React
14+
in Web Components [as described in the React documentation](https://reactjs.org/docs/web-components.html).
15+
Read on to find out what you can get by using it!
1316

1417
## Installation
1518

@@ -31,7 +34,7 @@ function Incrementer(): React.ReactElement {
3134
<button
3235
id="iterate-button"
3336
type="button"
34-
onClick={(): void => setIncrement(prevIncrement => prevIncrement + 1)}
37+
onClick={(): void => setIncrement((prevIncrement) => prevIncrement + 1)}
3538
>
3639
Increment
3740
</button>
@@ -50,27 +53,22 @@ import ReactHTMLElement from 'react-html-element';
5053

5154
class IncrementerComponent extends ReactHTMLElement {
5255
connectedCallback(): void {
53-
ReactDOM.render(<Incrementer />, this.mountPoint);
56+
this.render(<Incrementer />);
5457
}
5558
}
5659

5760
customElements.define('incrementer', ReactTestComponent);
5861
```
5962

60-
The key pieces of code are `... extends ReactHTMLElement` and `this.mountPoint`.
63+
The key pieces of code are `... extends ReactHTMLElement` and `this.render`,
64+
which mounts our app to its designated `mountPoint`, [as described below](#thismountpoint-and-using-custom-templates).
6165

6266
> ### Polyfills
63-
> One thing to remember is that you will need to load [the webcomponentsjs polyfills](https://www.webcomponents.org/polyfills) for `ReactHTMLElement` to work in all browsers. Be sure to include [the ES5 adapter](https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs#custom-elements-es5-adapterjs), as we currently transpile `ReactHTMLElement` down to ES5. The polyfills should be in the `<head>`, and should look something like this:
67+
>
68+
> One thing to remember is that you will need to load [the webcomponentsjs polyfills](https://www.webcomponents.org/polyfills) for `ReactHTMLElement` to work in all browsers.
6469
>
6570
> ```html
6671
> <script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js"></script>
67-
> <script>
68-
> if (!window.customElements) {
69-
> document.write('<!--');
70-
> }
71-
> </script>
72-
> <script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/custom-elements-es5-adapter.js"></script>
73-
> <!--- We use the closing bracket of this comment to close off the above opening comment, if it gets written -->
7472
> ```
7573
>
7674
> There are many ways to implement these polyfills, and you can explore them in the [webpcomponentsjs README](https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs#how-to-use).
@@ -94,9 +92,7 @@ This will allow us to utilize our Web Component as an element in any HTML:
9492
<script src="./path/to/incrementer.js"></script>
9593
</head>
9694
<body>
97-
<h1>
98-
Behold: An Incrementer
99-
</h1>
95+
<h1>Behold: An Incrementer</h1>
10096
<!-- put your web component in your html -->
10197
<incrementer></incrementer>
10298
</body>
@@ -114,7 +110,7 @@ import ReactHTMLElement from 'react-html-element';
114110

115111
class IncrementerComponent extends ReactHTMLElement {
116112
connectedCallback(): void {
117-
ReactDOM.render(<Incrementer />, this.mountPoint);
113+
this.render(<Incrementer />);
118114
}
119115

120116
constructor(): void {
@@ -134,21 +130,27 @@ customElements.define('incrementer', ReactTestComponent);
134130

135131
Using styled-components with ReactHTMLElement seems tricky, but there's actually a very simple way to implement it: the [`StyleSheetManager`](https://styled-components.com/docs/api#stylesheetmanager). An app rendered with `StyleSheetManager` might look like this:
136132

137-
```react
133+
```jsx
138134
class ReactWebComponent extends ReactHTMLElement {
139135
connectedCallback() {
140-
ReactDOM.render((
141-
<StyleSheetManager target={this.mountPoint.parentNode}>
136+
this.render(
137+
<StyleSheetManager target={this.shadow}>
142138
<App />
143139
</StyleSheetManager>
144-
), this.mountPoint);
140+
);
145141
}
146142
}
147143
```
148144

149-
We use `this.mountPoint.parentNode` for the styles instead of simply using `this.mountPoint` for the case of unmounting. If stylesheets are a child of `this.mountPoint`, ReactDOM will throw an error when you try to unmount. (`unmountComponentAtNode(): The node you're attempting to unmount was rendered by another copy of React.`) This error is a little cryptic, but the bottom line is that ReactDOM expects that everything inside the mounted node was generated by React itself. When we use the same node to place our styles, it breaks that expectation. Using the `parentNode` will cause the styles to be placed within the Shadow DOM, but not inside the same component where our app is mounted.
145+
`this.shadow` is a getter that will initialize your Web Component, attaching a Shadow
146+
Root with `{mode: 'open'}`, and setting the Shadow Root's innerHTML to your
147+
template or `<div></div>`. If this initialization has already occurred, it will
148+
simply return the previously created Shadow Root. `this.mountPoint` utilizes
149+
`this.shadow` as part of its work to generate the Shadow Root.
150+
151+
We use `this.shadow` for the styles instead of simply using `this.mountPoint` because of unmounting. If stylesheets are a child of `this.mountPoint`, ReactDOM will throw an error when you try to unmount. (`unmountComponentAtNode(): The node you're attempting to unmount was rendered by another copy of React.`) This error is a little cryptic, but the bottom line is that ReactDOM expects that everything inside the mounted node was generated by React itself. When we use the same node to place our styles, it breaks that expectation. Using the `this.shadow` will cause the styles to be placed as a first-child of the Shadow DOM, but not inside the same component where our app is mounted.
150152

151-
If you're using a [custom template](#thismountpoint-and-using-custom-templates), you can find a node for your `StyleSheetManager` target by searching through the `shadowRoot` in the same way you might search through `document.body`. Often, simply using `this.mountPoint.parentNode` will still work as expected, even with custom templates.
153+
If you're using a [custom template](#thismountpoint-and-using-custom-templates), you may need to set the target for your `StyleSheetManager` differently. Often, simply using `this.mountPoint.parentNode` will work as expected, even with custom templates, but this will depend on your template. (You may run into competing styles or have a very unusual use-case where placing a `style` tag as a sibling of your application causes some other issue.)
152154

153155
# Contributing
154156

0 commit comments

Comments
 (0)