Skip to content

Commit

Permalink
The enableCustomElementPropertySupport flag changes React's handlin…
Browse files Browse the repository at this point in the history
…g of custom elements in a way that is more useful that just treating every prop as an attribute. However when server rendering we have no choice but to serialize props as attributes. When this flag is on and React supports more prop types on the client like functions and objects the server implementation needs to be a bit more naunced in how it renders these components. With this flag on `false`, function, and object props are omitted entirely and `true` is normalized to `""`. There was a bug however in the implementation which caused children more complex than a single string to be omitted because it matched the object type filter. This change reorganizes the code a bit to put these filters in the default prop handline case, leaving children, style, and innerHTML to be handled via normal logic.
  • Loading branch information
gnoff committed Oct 12, 2023
1 parent ea8a861 commit 78db6ca
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 22 deletions.
41 changes: 19 additions & 22 deletions packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -3134,32 +3134,13 @@ function pushStartCustomElement(

let children = null;
let innerHTML = null;
for (let propKey in props) {
for (const propKey in props) {
if (hasOwnProperty.call(props, propKey)) {
let propValue = props[propKey];
if (propValue == null) {
continue;
}
if (
enableCustomElementPropertySupport &&
(typeof propValue === 'function' || typeof propValue === 'object')
) {
// It is normal to render functions and objects on custom elements when
// client rendering, but when server rendering the output isn't useful,
// so skip it.
continue;
}
if (enableCustomElementPropertySupport && propValue === false) {
continue;
}
if (enableCustomElementPropertySupport && propValue === true) {
propValue = '';
}
if (enableCustomElementPropertySupport && propKey === 'className') {
// className gets rendered as class on the client, so it should be
// rendered as class on the server.
propKey = 'class';
}
let attributeName = propKey;
switch (propKey) {
case 'children':
children = propValue;
Expand All @@ -3174,15 +3155,31 @@ function pushStartCustomElement(
case 'suppressHydrationWarning':
// Ignored. These are built-in to React on the client.
break;
case 'className':
if (enableCustomElementPropertySupport) {
// className gets rendered as class on the client, so it should be
// rendered as class on the server.
attributeName = 'class';
}
// intentional fallthrough
default:
if (
isAttributeNameSafe(propKey) &&
typeof propValue !== 'function' &&
typeof propValue !== 'symbol'
) {
if (enableCustomElementPropertySupport) {
if (propValue === false) {
continue;
} else if (propValue === true) {
propValue = '';
} else if (typeof propValue === 'object') {
continue;
}
}
target.push(
attributeSeparator,
stringToChunk(propKey),
stringToChunk(attributeName),
attributeAssign,
stringToChunk(escapeTextForBrowser(propValue)),
attributeEnd,
Expand Down
26 changes: 26 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3624,6 +3624,32 @@ describe('ReactDOMFizzServer', () => {
);
});

// bugfix: https://github.com/facebook/react/issues/27286 affecting enableCustomElementPropertySupport flag
it('can render custom elements with children on ther server', async () => {
await act(() => {
renderToPipeableStream(
<html>
<body>
<my-element>
<div>foo</div>
</my-element>
</body>
</html>,
).pipe(writable);
});

expect(getVisibleChildren(document)).toEqual(
<html>
<head />
<body>
<my-element>
<div>foo</div>
</my-element>
</body>
</html>,
);
});

describe('error escaping', () => {
it('escapes error hash, message, and component stack values in directly flushed errors (html escaping)', async () => {
window.__outlet = {};
Expand Down

0 comments on commit 78db6ca

Please sign in to comment.