Allow functions to be passed to custom element setters (#23042)
This is part of the new custom element features that were implemented here: https://github.com/facebook/react/commit/24dd07bd269590ee5024b7f0f1906887d256ea86 When a custom element has a setter for a property and passes the `in` heuristic, the value passed to the react property should be assigned directly to the custom element's property, regardless of the type of the value. However, it was discovered that this isn't working with functions. This patch makes it work with functions. Fixes https://github.com/facebook/react/issues/23041
Joey Arhar committed
Jan 12, 2022 at 13:12 UTC
a87adefecdff672d5261e93945c227ad72c5444c
2 files changed
+33
-4
packages/react-dom/src/__tests__/DOMPropertyOperations-test.js
+29
@@ -504,6 +504,35 @@ describe('DOMPropertyOperations', () => {
504
expect(customElement.foo).toBe('two');
505
expect(customElement.getAttribute('foo')).toBe('one');
506
});
507
+
508
+ // @gate enableCustomElementPropertySupport
509
+ it('custom element properties should accept functions', () => {
510
+ const container = document.createElement('div');
511
+ document.body.appendChild(container);
512
+ ReactDOM.render(<my-custom-element />, container);
513
+ const customElement = container.querySelector('my-custom-element');
514
+
515
+ // Install a setter to activate the `in` heuristic
516
+ Object.defineProperty(customElement, 'foo', {
517
+ set: function(x) {
518
+ this._foo = x;
519
+ },
520
+ get: function() {
521
+ return this._foo;
522
+ },
523
+ });
524
+ function myFunction() {
525
+ return 'this is myFunction';
526
+ }
527
+ ReactDOM.render(<my-custom-element foo={myFunction} />, container);
528
+ expect(customElement.foo).toBe(myFunction);
529
+
530
+ // Also remove and re-add the property for good measure
531
+ ReactDOM.render(<my-custom-element />, container);
532
+ expect(customElement.foo).toBe(null);
533
+ ReactDOM.render(<my-custom-element foo={myFunction} />, container);
534
+ expect(customElement.foo).toBe(myFunction);
535
+ });
536
});
537
538
describe('deleteValueForProperty', () => {
packages/react-dom/src/client/DOMPropertyOperations.js
+4
-4
@@ -184,10 +184,6 @@ export function setValueForProperty(
184
}
185
}
186
187
- if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) {
188
- value = null;
189
- }
190
-
187
if (
188
enableCustomElementPropertySupport &&
189
isCustomComponentTag &&
@@ -197,6 +193,10 @@ export function setValueForProperty(
193
return;
194
}
195
196
+ if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) {
197
+ value = null;
198
+ }
199
+
200
// If the prop isn't in the special list, treat it as a simple attribute.
201
if (isCustomComponentTag || propertyInfo === null) {
202
if (isAttributeNameSafe(name)) {