@samitouri / QOS-React / commits / 6fb8133ed3

Turn on string ref deprecation warning for everybody (not codemoddable) (#25383)

## Summary Alternate to https://github.com/facebook/react/pull/25334 without any prod runtime changes i.e. the proposed codemod in https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#deprecate-string-refs-and-remove-production-mode-_owner-field would not work. ## How did you test this change? - [x] CI - [x] `yarn test` with and without `warnAboutStringRefs`

Sebastian Silbermann committed Nov 17, 2022 at 01:15 UTC 6fb8133ed3aa6b23063375dd345c6e413b05f0fe
37 files changed +591 -300
packages/react-dom/src/__tests__/ReactComponent-test.js
+25 -4
@@ -12,6 +12,7 @@
12 let React;
13 let ReactDOM;
14 let ReactDOMServer;
15 +let ReactFeatureFlags;
16 let ReactTestUtils;
17
18 describe('ReactComponent', () => {
@@ -21,6 +22,7 @@ describe('ReactComponent', () => {
22 React = require('react');
23 ReactDOM = require('react-dom');
24 ReactDOMServer = require('react-dom/server');
25 + ReactFeatureFlags = require('shared/ReactFeatureFlags');
26 ReactTestUtils = require('react-dom/test-utils');
27 });
28
@@ -36,7 +38,7 @@ describe('ReactComponent', () => {
38 }).toThrowError(/Target container is not a DOM element./);
39 });
40
39 - it('should throw when supplying a ref outside of render method', () => {
41 + it('should throw when supplying a string ref outside of render method', () => {
42 let instance = <div ref="badDiv" />;
43 expect(function() {
44 instance = ReactTestUtils.renderIntoDocument(instance);
@@ -102,7 +104,7 @@ describe('ReactComponent', () => {
104 }
105 });
106
105 - it('should support refs on owned components', () => {
107 + it('should support string refs on owned components', () => {
108 const innerObj = {};
109 const outerObj = {};
110
@@ -133,10 +135,29 @@ describe('ReactComponent', () => {
135 }
136 }
137
136 - ReactTestUtils.renderIntoDocument(<Component />);
138 + expect(() => {
139 + ReactTestUtils.renderIntoDocument(<Component />);
140 + }).toErrorDev(
141 + ReactFeatureFlags.warnAboutStringRefs
142 + ? [
143 + 'Warning: Component "div" contains the string ref "inner". ' +
144 + 'Support for string refs will be removed in a future major release. ' +
145 + 'We recommend using useRef() or createRef() instead. ' +
146 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
147 + ' in div (at **)\n' +
148 + ' in Wrapper (at **)\n' +
149 + ' in Component (at **)',
150 + 'Warning: Component "Component" contains the string ref "outer". ' +
151 + 'Support for string refs will be removed in a future major release. ' +
152 + 'We recommend using useRef() or createRef() instead. ' +
153 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
154 + ' in Component (at **)',
155 + ]
156 + : [],
157 + );
158 });
159
139 - it('should not have refs on unmounted components', () => {
160 + it('should not have string refs on unmounted components', () => {
161 class Parent extends React.Component {
162 render() {
163 return (
packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
+4 -2
@@ -378,7 +378,7 @@ describe('ReactComponentLifeCycle', () => {
378 }
379 // you would *NEVER* do anything like this in real code!
380 this.state.hasRenderCompleted = true;
381 - return <div ref="theDiv">I am the inner DIV</div>;
381 + return <div ref={React.createRef()}>I am the inner DIV</div>;
382 }
383
384 componentWillUnmount() {
@@ -477,7 +477,9 @@ describe('ReactComponentLifeCycle', () => {
477 class Component extends React.Component {
478 render() {
479 return (
480 - <Tooltip ref="tooltip" tooltip={<div>{this.props.tooltipText}</div>}>
480 + <Tooltip
481 + ref={React.createRef()}
482 + tooltip={<div>{this.props.tooltipText}</div>}>
483 {this.props.text}
484 </Tooltip>
485 );
packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
+37 -26
@@ -72,6 +72,8 @@ describe('ReactCompositeComponent', () => {
72 MorphingComponent = class extends React.Component {
73 state = {activated: false};
74
75 + xRef = React.createRef();
76 +
77 _toggleActivatedState = () => {
78 this.setState({activated: !this.state.activated});
79 };
@@ -79,9 +81,9 @@ describe('ReactCompositeComponent', () => {
81 render() {
82 const toggleActivatedState = this._toggleActivatedState;
83 return !this.state.activated ? (
82 - <a ref="x" onClick={toggleActivatedState} />
84 + <a ref={this.xRef} onClick={toggleActivatedState} />
85 ) : (
84 - <b ref="x" onClick={toggleActivatedState} />
86 + <b ref={this.xRef} onClick={toggleActivatedState} />
87 );
88 }
89 };
@@ -91,14 +93,16 @@ describe('ReactCompositeComponent', () => {
93 * reallocated again.
94 */
95 ChildUpdates = class extends React.Component {
96 + anchorRef = React.createRef();
97 +
98 getAnchor = () => {
95 - return this.refs.anch;
99 + return this.anchorRef.current;
100 };
101
102 render() {
103 const className = this.props.anchorClassOn ? 'anchorClass' : '';
104 return this.props.renderAnchor ? (
101 - <a ref="anch" className={className} />
105 + <a ref={this.anchorRef} className={className} />
106 ) : (
107 <b />
108 );
@@ -186,11 +190,11 @@ describe('ReactCompositeComponent', () => {
190 it('should rewire refs when rendering to different child types', () => {
191 const instance = ReactTestUtils.renderIntoDocument(<MorphingComponent />);
192
189 - expect(instance.refs.x.tagName).toBe('A');
193 + expect(instance.xRef.current.tagName).toBe('A');
194 instance._toggleActivatedState();
191 - expect(instance.refs.x.tagName).toBe('B');
195 + expect(instance.xRef.current.tagName).toBe('B');
196 instance._toggleActivatedState();
193 - expect(instance.refs.x.tagName).toBe('A');
197 + expect(instance.xRef.current.tagName).toBe('A');
198 });
199
200 it('should not cache old DOM nodes when switching constructors', () => {
@@ -739,10 +743,13 @@ describe('ReactCompositeComponent', () => {
743 }
744
745 class Wrapper extends React.Component {
746 + parentRef = React.createRef();
747 + childRef = React.createRef();
748 +
749 render() {
750 return (
744 - <Parent ref="parent">
745 - <Child ref="child" />
751 + <Parent ref={this.parentRef}>
752 + <Child ref={this.childRef} />
753 </Parent>
754 );
755 }
@@ -750,14 +757,14 @@ describe('ReactCompositeComponent', () => {
757
758 const wrapper = ReactTestUtils.renderIntoDocument(<Wrapper />);
759
753 - expect(wrapper.refs.parent.state.flag).toEqual(true);
754 - expect(wrapper.refs.child.context).toEqual({flag: true});
760 + expect(wrapper.parentRef.current.state.flag).toEqual(true);
761 + expect(wrapper.childRef.current.context).toEqual({flag: true});
762
763 // We update <Parent /> while <Child /> is still a static prop relative to this update
757 - wrapper.refs.parent.setState({flag: false});
764 + wrapper.parentRef.current.setState({flag: false});
765
759 - expect(wrapper.refs.parent.state.flag).toEqual(false);
760 - expect(wrapper.refs.child.context).toEqual({flag: false});
766 + expect(wrapper.parentRef.current.state.flag).toEqual(false);
767 + expect(wrapper.childRef.current.context).toEqual({flag: false});
768 });
769
770 it('should pass context transitively', () => {
@@ -1142,14 +1149,17 @@ describe('ReactCompositeComponent', () => {
1149 }
1150
1151 class Component extends React.Component {
1152 + static0Ref = React.createRef();
1153 + static1Ref = React.createRef();
1154 +
1155 render() {
1156 if (this.props.flipped) {
1157 return (
1158 <div>
1149 - <Static ref="static0" key="B">
1159 + <Static ref={this.static0Ref} key="B">
1160 B (ignored)
1161 </Static>
1152 - <Static ref="static1" key="A">
1162 + <Static ref={this.static1Ref} key="A">
1163 A (ignored)
1164 </Static>
1165 </div>
@@ -1157,10 +1167,10 @@ describe('ReactCompositeComponent', () => {
1167 } else {
1168 return (
1169 <div>
1160 - <Static ref="static0" key="A">
1170 + <Static ref={this.static0Ref} key="A">
1171 A
1172 </Static>
1163 - <Static ref="static1" key="B">
1173 + <Static ref={this.static1Ref} key="B">
1174 B
1175 </Static>
1176 </div>
@@ -1171,14 +1181,14 @@ describe('ReactCompositeComponent', () => {
1181
1182 const container = document.createElement('div');
1183 const comp = ReactDOM.render(<Component flipped={false} />, container);
1174 - expect(ReactDOM.findDOMNode(comp.refs.static0).textContent).toBe('A');
1175 - expect(ReactDOM.findDOMNode(comp.refs.static1).textContent).toBe('B');
1184 + expect(ReactDOM.findDOMNode(comp.static0Ref.current).textContent).toBe('A');
1185 + expect(ReactDOM.findDOMNode(comp.static1Ref.current).textContent).toBe('B');
1186
1187 // When flipping the order, the refs should update even though the actual
1188 // contents do not
1189 ReactDOM.render(<Component flipped={true} />, container);
1180 - expect(ReactDOM.findDOMNode(comp.refs.static0).textContent).toBe('B');
1181 - expect(ReactDOM.findDOMNode(comp.refs.static1).textContent).toBe('A');
1190 + expect(ReactDOM.findDOMNode(comp.static0Ref.current).textContent).toBe('B');
1191 + expect(ReactDOM.findDOMNode(comp.static1Ref.current).textContent).toBe('A');
1192 });
1193
1194 it('should allow access to findDOMNode in componentWillUnmount', () => {
@@ -1453,10 +1463,11 @@ describe('ReactCompositeComponent', () => {
1463 this.state = {
1464 color: 'green',
1465 };
1466 + this.appleRef = React.createRef();
1467 }
1468
1469 render() {
1459 - return <Apple color={this.state.color} ref="apple" />;
1470 + return <Apple color={this.state.color} ref={this.appleRef} />;
1471 }
1472 }
1473
@@ -1502,15 +1513,15 @@ describe('ReactCompositeComponent', () => {
1513 expect(renderCalls).toBe(2);
1514
1515 // Re-render base on state
1505 - instance.refs.apple.cut();
1516 + instance.appleRef.current.cut();
1517 expect(renderCalls).toBe(3);
1518
1519 // No re-render based on state
1509 - instance.refs.apple.cut();
1520 + instance.appleRef.current.cut();
1521 expect(renderCalls).toBe(3);
1522
1523 // Re-render based on state again
1513 - instance.refs.apple.eatSlice();
1524 + instance.appleRef.current.eatSlice();
1525 expect(renderCalls).toBe(4);
1526 });
1527
packages/react-dom/src/__tests__/ReactDOMEventListener-test.js
+3 -2
@@ -193,12 +193,13 @@ describe('ReactDOMEventListener', () => {
193 const onMouseOut = event => mouseOut(event.target);
194
195 class Wrapper extends React.Component {
196 + innerRef = React.createRef();
197 getInner = () => {
197 - return this.refs.inner;
198 + return this.innerRef.current;
199 };
200
201 render() {
201 - const inner = <div ref="inner">Inner</div>;
202 + const inner = <div ref={this.innerRef}>Inner</div>;
203 return (
204 <div>
205 <div onMouseOut={onMouseOut} id="outer">
packages/react-dom/src/__tests__/ReactDOMInput-test.js
+15 -6
@@ -1071,22 +1071,31 @@ describe('ReactDOMInput', () => {
1071
1072 it('should control radio buttons', () => {
1073 class RadioGroup extends React.Component {
1074 + aRef = React.createRef();
1075 + bRef = React.createRef();
1076 + cRef = React.createRef();
1077 +
1078 render() {
1079 return (
1080 <div>
1081 <input
1078 - ref="a"
1082 + ref={this.aRef}
1083 type="radio"
1084 name="fruit"
1085 checked={true}
1086 onChange={emptyFunction}
1087 />
1088 A
1085 - <input ref="b" type="radio" name="fruit" onChange={emptyFunction} />
1089 + <input
1090 + ref={this.bRef}
1091 + type="radio"
1092 + name="fruit"
1093 + onChange={emptyFunction}
1094 + />
1095 B
1096 <form>
1097 <input
1089 - ref="c"
1098 + ref={this.cRef}
1099 type="radio"
1100 name="fruit"
1101 defaultChecked={true}
@@ -1099,9 +1108,9 @@ describe('ReactDOMInput', () => {
1108 }
1109
1110 const stub = ReactDOM.render(<RadioGroup />, container);
1102 - const aNode = stub.refs.a;
1103 - const bNode = stub.refs.b;
1104 - const cNode = stub.refs.c;
1111 + const aNode = stub.aRef.current;
1112 + const bNode = stub.bRef.current;
1113 + const cNode = stub.cRef.current;
1114
1115 expect(aNode.checked).toBe(true);
1116 expect(bNode.checked).toBe(false);
packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
+1 -1
@@ -337,7 +337,7 @@ describe('ReactDOMServerIntegration', () => {
337 itRenders('no ref attribute', async render => {
338 class RefComponent extends React.Component {
339 render() {
340 - return <div ref="foo" />;
340 + return <div ref={React.createRef()} />;
341 }
342 }
343 const e = await render(<RefComponent />);
packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
+18 -4
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
14 let React;
15 let ReactDOM;
16 let ReactDOMServer;
17 +let ReactFeatureFlags;
18 let ReactTestUtils;
19
20 function initModules() {
@@ -22,6 +23,7 @@ function initModules() {
23 React = require('react');
24 ReactDOM = require('react-dom');
25 ReactDOMServer = require('react-dom/server');
26 + ReactFeatureFlags = require('shared/ReactFeatureFlags');
27 ReactTestUtils = require('react-dom/test-utils');
28
29 // Make them available to the helpers.
@@ -91,10 +93,22 @@ describe('ReactDOMServerIntegration', () => {
93 root.innerHTML = markup;
94 let component = null;
95 resetModules();
94 - await asyncReactDOMRender(
95 - <RefsComponent ref={e => (component = e)} />,
96 - root,
97 - true,
96 + await expect(async () => {
97 + await asyncReactDOMRender(
98 + <RefsComponent ref={e => (component = e)} />,
99 + root,
100 + true,
101 + );
102 + }).toErrorDev(
103 + ReactFeatureFlags.warnAboutStringRefs
104 + ? [
105 + 'Warning: Component "RefsComponent" contains the string ref "myDiv". ' +
106 + 'Support for string refs will be removed in a future major release. ' +
107 + 'We recommend using useRef() or createRef() instead. ' +
108 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
109 + ' in RefsComponent (at **)',
110 + ]
111 + : [],
112 );
113 expect(component.refs.myDiv).toBe(root.firstChild);
114 });
packages/react-dom/src/__tests__/ReactIdentity-test.js
+3 -2
@@ -67,17 +67,18 @@ describe('ReactIdentity', () => {
67
68 function renderAComponentWithKeyIntoContainer(key, container) {
69 class Wrapper extends React.Component {
70 + spanRef = React.createRef();
71 render() {
72 return (
73 <div>
73 - <span ref="span" key={key} />
74 + <span ref={this.spanRef} key={key} />
75 </div>
76 );
77 }
78 }
79
80 const instance = ReactDOM.render(<Wrapper />, container);
80 - const span = instance.refs.span;
81 + const span = instance.spanRef.current;
82 expect(span).not.toBe(null);
83 }
84
packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js
+7 -3
@@ -60,6 +60,8 @@ class StatusDisplay extends React.Component {
60 * Displays friends statuses.
61 */
62 class FriendsStatusDisplay extends React.Component {
63 + displays = {};
64 +
65 /**
66 * Gets the order directly from each rendered child's `index` field.
67 * Refs are not maintained in the rendered order, and neither is
@@ -84,7 +86,7 @@ class FriendsStatusDisplay extends React.Component {
86 const originalKeys = this.getOriginalKeys();
87 for (let i = 0; i < originalKeys.length; i++) {
88 const key = originalKeys[i];
87 - res[key] = this.refs[key];
89 + res[key] = this.displays[key];
90 }
91 return res;
92 }
@@ -104,7 +106,7 @@ class FriendsStatusDisplay extends React.Component {
106 // We are only interested in children up to the current key.
107 return;
108 }
107 - expect(this.refs[key]).toBeTruthy();
109 + expect(this.displays[key]).toBeTruthy();
110 }
111 }
112
@@ -116,7 +118,9 @@ class FriendsStatusDisplay extends React.Component {
118 !status ? null : (
119 <StatusDisplay
120 key={key}
119 - ref={key}
121 + ref={current => {
122 + this.displays[key] = current;
123 + }}
124 contentKey={key}
125 onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
126 status={status}
packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+5 -3
@@ -36,6 +36,8 @@ describe('ReactDOMServerHydration', () => {
36 let numClicks = 0;
37
38 class TestComponent extends React.Component {
39 + spanRef = React.createRef();
40 +
41 componentDidMount() {
42 mountCount++;
43 }
@@ -46,7 +48,7 @@ describe('ReactDOMServerHydration', () => {
48
49 render() {
50 return (
49 - <span ref="span" onClick={this.click}>
51 + <span ref={this.spanRef} onClick={this.click}>
52 Name: {this.props.name}
53 </span>
54 );
@@ -89,7 +91,7 @@ describe('ReactDOMServerHydration', () => {
91
92 // Ensure the events system works after mount into server markup
93 expect(numClicks).toEqual(0);
92 - instance.refs.span.click();
94 + instance.spanRef.current.click();
95 expect(numClicks).toEqual(1);
96
97 ReactDOM.unmountComponentAtNode(element);
@@ -107,7 +109,7 @@ describe('ReactDOMServerHydration', () => {
109
110 // Ensure the events system works after markup mismatch.
111 expect(numClicks).toEqual(1);
110 - instance.refs.span.click();
112 + instance.spanRef.current.click();
113 expect(numClicks).toEqual(2);
114 } finally {
115 document.body.removeChild(element);
packages/react-dom/src/__tests__/ReactTestUtils-test.js
+16 -11
@@ -221,13 +221,17 @@ describe('ReactTestUtils', () => {
221 // Full-page components (html, head, body) can't be rendered into a div
222 // directly...
223 class Root extends React.Component {
224 + htmlRef = React.createRef();
225 + headRef = React.createRef();
226 + bodyRef = React.createRef();
227 +
228 render() {
229 return (
226 - <html ref="html">
227 - <head ref="head">
230 + <html ref={this.htmlRef}>
231 + <head ref={this.headRef}>
232 <title>hello</title>
233 </head>
230 - <body ref="body">hello, world</body>
234 + <body ref={this.bodyRef}>hello, world</body>
235 </html>
236 );
237 }
@@ -237,12 +241,12 @@ describe('ReactTestUtils', () => {
241 const testDocument = getTestDocument(markup);
242 const component = ReactDOM.hydrate(<Root />, testDocument);
243
240 - expect(component.refs.html.tagName).toBe('HTML');
241 - expect(component.refs.head.tagName).toBe('HEAD');
242 - expect(component.refs.body.tagName).toBe('BODY');
243 - expect(ReactTestUtils.isDOMComponent(component.refs.html)).toBe(true);
244 - expect(ReactTestUtils.isDOMComponent(component.refs.head)).toBe(true);
245 - expect(ReactTestUtils.isDOMComponent(component.refs.body)).toBe(true);
244 + expect(component.htmlRef.current.tagName).toBe('HTML');
245 + expect(component.headRef.current.tagName).toBe('HEAD');
246 + expect(component.bodyRef.current.tagName).toBe('BODY');
247 + expect(ReactTestUtils.isDOMComponent(component.htmlRef.current)).toBe(true);
248 + expect(ReactTestUtils.isDOMComponent(component.headRef.current)).toBe(true);
249 + expect(ReactTestUtils.isDOMComponent(component.bodyRef.current)).toBe(true);
250 });
251
252 it('can scry with stateless components involved', () => {
@@ -348,12 +352,13 @@ describe('ReactTestUtils', () => {
352
353 it('should change the value of an input field in a component', () => {
354 class SomeComponent extends React.Component {
355 + inputRef = React.createRef();
356 render() {
357 return (
358 <div>
359 <input
360 type="text"
356 - ref="input"
361 + ref={this.inputRef}
362 onChange={this.props.handleChange}
363 />
364 </div>
@@ -373,7 +378,7 @@ describe('ReactTestUtils', () => {
378 container,
379 );
380
376 - const node = instance.refs.input;
381 + const node = instance.inputRef.current;
382 node.value = 'zebra';
383 ReactTestUtils.Simulate.change(node);
384
packages/react-dom/src/__tests__/ReactUpdates-test.js
+35 -19
@@ -147,6 +147,7 @@ describe('ReactUpdates', () => {
147
148 class Parent extends React.Component {
149 state = {x: 0};
150 + childRef = React.createRef();
151
152 componentDidUpdate() {
153 parentUpdateCount++;
@@ -155,7 +156,7 @@ describe('ReactUpdates', () => {
156 render() {
157 return (
158 <div>
158 - <Child ref="child" x={this.state.x} />
159 + <Child ref={this.childRef} x={this.state.x} />
160 </div>
161 );
162 }
@@ -176,7 +177,7 @@ describe('ReactUpdates', () => {
177 }
178
179 const instance = ReactTestUtils.renderIntoDocument(<Parent />);
179 - const child = instance.refs.child;
180 + const child = instance.childRef.current;
181 expect(instance.state.x).toBe(0);
182 expect(child.state.y).toBe(0);
183
@@ -200,6 +201,7 @@ describe('ReactUpdates', () => {
201
202 class Parent extends React.Component {
203 state = {x: 0};
204 + childRef = React.createRef();
205
206 componentDidUpdate() {
207 parentUpdateCount++;
@@ -208,7 +210,7 @@ describe('ReactUpdates', () => {
210 render() {
211 return (
212 <div>
211 - <Child ref="child" x={this.state.x} />
213 + <Child ref={this.childRef} x={this.state.x} />
214 </div>
215 );
216 }
@@ -229,7 +231,7 @@ describe('ReactUpdates', () => {
231 }
232
233 const instance = ReactTestUtils.renderIntoDocument(<Parent />);
232 - const child = instance.refs.child;
234 + const child = instance.childRef.current;
235 expect(instance.state.x).toBe(0);
236 expect(child.state.y).toBe(0);
237
@@ -336,13 +338,15 @@ describe('ReactUpdates', () => {
338 let childRenderCount = 0;
339
340 class Parent extends React.Component {
341 + childRef = React.createRef();
342 +
343 shouldComponentUpdate() {
344 return false;
345 }
346
347 render() {
348 parentRenderCount++;
345 - return <Child ref="child" />;
349 + return <Child ref={this.childRef} />;
350 }
351 }
352
@@ -370,7 +374,7 @@ describe('ReactUpdates', () => {
374 expect(childRenderCount).toBe(1);
375
376 ReactDOM.unstable_batchedUpdates(function() {
373 - instance.refs.child.setState({x: 1});
377 + instance.childRef.current.setState({x: 1});
378 });
379
380 expect(parentRenderCount).toBe(1);
@@ -428,28 +432,34 @@ describe('ReactUpdates', () => {
432 };
433
434 class Box extends React.Component {
435 + boxDivRef = React.createRef();
436 +
437 render() {
432 - return <div ref="boxDiv">{this.props.children}</div>;
438 + return <div ref={this.boxDivRef}>{this.props.children}</div>;
439 }
440 }
441 Object.assign(Box.prototype, UpdateLoggingMixin);
442
443 class Child extends React.Component {
444 + spanRef = React.createRef();
445 +
446 render() {
439 - return <span ref="span">child</span>;
447 + return <span ref={this.spanRef}>child</span>;
448 }
449 }
450 Object.assign(Child.prototype, UpdateLoggingMixin);
451
452 class Switcher extends React.Component {
453 state = {tabKey: 'hello'};
454 + boxRef = React.createRef();
455 + switcherDivRef = React.createRef();
456 render() {
457 const child = this.props.children;
458
459 return (
450 - <Box ref="box">
460 + <Box ref={this.boxRef}>
461 <div
452 - ref="switcherDiv"
462 + ref={this.switcherDivRef}
463 style={{
464 display: this.state.tabKey === child.key ? '' : 'none',
465 }}>
@@ -462,10 +472,13 @@ describe('ReactUpdates', () => {
472 Object.assign(Switcher.prototype, UpdateLoggingMixin);
473
474 class App extends React.Component {
475 + switcherRef = React.createRef();
476 + childRef = React.createRef();
477 +
478 render() {
479 return (
467 - <Switcher ref="switcher">
468 - <Child key="hello" ref="child" />
480 + <Switcher ref={this.switcherRef}>
481 + <Child key="hello" ref={this.childRef} />
482 </Switcher>
483 );
484 }
@@ -513,21 +526,21 @@ describe('ReactUpdates', () => {
526 expectUpdates(desiredWillUpdates, desiredDidUpdates);
527 }
528 testUpdates(
516 - [root.refs.switcher.refs.box, root.refs.switcher],
529 + [root.switcherRef.current.boxRef.current, root.switcherRef.current],
530 // Owner-child relationships have inverse will and did
531 ['Switcher', 'Box'],
532 ['Box', 'Switcher'],
533 );
534
535 testUpdates(
523 - [root.refs.child, root.refs.switcher.refs.box],
536 + [root.childRef.current, root.switcherRef.current.boxRef.current],
537 // Not owner-child so reconcile independently
538 ['Box', 'Child'],
539 ['Box', 'Child'],
540 );
541
542 testUpdates(
530 - [root.refs.child, root.refs.switcher],
543 + [root.childRef.current, root.switcherRef.current],
544 // Switcher owns Box and Child, Box does not own Child
545 ['Switcher', 'Box', 'Child'],
546 ['Box', 'Switcher', 'Child'],
@@ -588,12 +601,13 @@ describe('ReactUpdates', () => {
601
602 class Outer extends React.Component {
603 state = {x: 0};
604 + innerRef = React.createRef();
605
606 render() {
607 updates.push('Outer-render-' + this.state.x);
608 return (
609 <div>
596 - <Inner x={this.state.x} ref="inner" />
610 + <Inner x={this.state.x} ref={this.innerRef} />
611 </div>
612 );
613 }
@@ -602,7 +616,7 @@ describe('ReactUpdates', () => {
616 const x = this.state.x;
617 updates.push('Outer-didUpdate-' + x);
618 updates.push('Inner-setState-' + x);
605 - this.refs.inner.setState({x: x}, function() {
619 + this.innerRef.current.setState({x: x}, function() {
620 updates.push('Inner-callback-' + x);
621 });
622 }
@@ -945,12 +959,14 @@ describe('ReactUpdates', () => {
959
960 it('does not update one component twice in a batch (#2410)', () => {
961 class Parent extends React.Component {
962 + childRef = React.createRef();
963 +
964 getChild = () => {
949 - return this.refs.child;
965 + return this.childRef.current;
966 };
967
968 render() {
953 - return <Child ref="child" />;
969 + return <Child ref={this.childRef} />;
970 }
971 }
972
packages/react-dom/src/__tests__/refs-destruction-test.js
+29 -33
@@ -30,6 +30,9 @@ describe('refs-destruction', () => {
30 }
31
32 TestComponent = class extends React.Component {
33 + theInnerDivRef = React.createRef();
34 + theInnerClassComponentRef = React.createRef();
35 +
36 render() {
37 if (this.props.destroy) {
38 return <div />;
@@ -43,8 +46,8 @@ describe('refs-destruction', () => {
46 } else {
47 return (
48 <div>
46 - <div ref="theInnerDiv" />
47 - <ClassComponent ref="theInnerClassComponent" />
49 + <div ref={this.theInnerDivRef} />
50 + <ClassComponent ref={this.theInnerClassComponentRef} />
51 </div>
52 );
53 }
@@ -55,52 +58,45 @@ describe('refs-destruction', () => {
58 it('should remove refs when destroying the parent', () => {
59 const container = document.createElement('div');
60 const testInstance = ReactDOM.render(<TestComponent />, container);
58 - expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
59 - true,
60 - );
61 +
62 expect(
62 - Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key])
63 - .length,
64 - ).toEqual(2);
63 + ReactTestUtils.isDOMComponent(testInstance.theInnerDivRef.current),
64 + ).toBe(true);
65 + expect(testInstance.theInnerClassComponentRef.current).toBeTruthy();
66 +
67 ReactDOM.unmountComponentAtNode(container);
66 - expect(
67 - Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key])
68 - .length,
69 - ).toEqual(0);
68 +
69 + expect(testInstance.theInnerDivRef.current).toBe(null);
70 + expect(testInstance.theInnerClassComponentRef.current).toBe(null);
71 });
72
73 it('should remove refs when destroying the child', () => {
74 const container = document.createElement('div');
75 const testInstance = ReactDOM.render(<TestComponent />, container);
75 - expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
76 - true,
77 - );
76 expect(
79 - Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key])
80 - .length,
81 - ).toEqual(2);
77 + ReactTestUtils.isDOMComponent(testInstance.theInnerDivRef.current),
78 + ).toBe(true);
79 + expect(testInstance.theInnerClassComponentRef.current).toBeTruthy();
80 +
81 ReactDOM.render(<TestComponent destroy={true} />, container);
83 - expect(
84 - Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key])
85 - .length,
86 - ).toEqual(0);
82 +
83 + expect(testInstance.theInnerDivRef.current).toBe(null);
84 + expect(testInstance.theInnerClassComponentRef.current).toBe(null);
85 });
86
87 it('should remove refs when removing the child ref attribute', () => {
88 const container = document.createElement('div');
89 const testInstance = ReactDOM.render(<TestComponent />, container);
92 - expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
93 - true,
94 - );
90 +
91 expect(
96 - Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key])
97 - .length,
98 - ).toEqual(2);
92 + ReactTestUtils.isDOMComponent(testInstance.theInnerDivRef.current),
93 + ).toBe(true);
94 + expect(testInstance.theInnerClassComponentRef.current).toBeTruthy();
95 +
96 ReactDOM.render(<TestComponent removeRef={true} />, container);
100 - expect(
101 - Object.keys(testInstance.refs || {}).filter(key => testInstance.refs[key])
102 - .length,
103 - ).toEqual(0);
97 +
98 + expect(testInstance.theInnerDivRef.current).toBe(null);
99 + expect(testInstance.theInnerClassComponentRef.current).toBe(null);
100 });
101
102 it('should not error when destroying child with ref asynchronously', () => {
@@ -135,7 +131,7 @@ describe('refs-destruction', () => {
131 render() {
132 return (
133 <Modal>
138 - <a ref="ref" />
134 + <a ref={React.createRef()} />
135 </Modal>
136 );
137 }
packages/react-dom/src/__tests__/refs-test.js
+180 -102
@@ -11,86 +11,12 @@
11
12 let React = require('react');
13 let ReactDOM = require('react-dom');
14 +let ReactFeatureFlags = require('shared/ReactFeatureFlags');
15 let ReactTestUtils = require('react-dom/test-utils');
16
16 -/**
17 - * Counts clicks and has a renders an item for each click. Each item rendered
18 - * has a ref of the form "clickLogN".
19 - */
20 -class ClickCounter extends React.Component {
21 - state = {count: this.props.initialCount};
22 -
23 - triggerReset = () => {
24 - this.setState({count: this.props.initialCount});
25 - };
26 -
27 - handleClick = () => {
28 - this.setState({count: this.state.count + 1});
29 - };
30 -
31 - render() {
32 - const children = [];
33 - let i;
34 - for (i = 0; i < this.state.count; i++) {
35 - children.push(
36 - <div
37 - className="clickLogDiv"
38 - key={'clickLog' + i}
39 - ref={'clickLog' + i}
40 - />,
41 - );
42 - }
43 - return (
44 - <span className="clickIncrementer" onClick={this.handleClick}>
45 - {children}
46 - </span>
47 - );
48 - }
49 -}
50 -
51 -/**
52 - * Only purpose is to test that refs are tracked even when applied to a
53 - * component that is injected down several layers. Ref systems are difficult to
54 - * build in such a way that ownership is maintained in an airtight manner.
55 - */
56 -class GeneralContainerComponent extends React.Component {
57 - render() {
58 - return <div>{this.props.children}</div>;
59 - }
60 -}
61 -
62 -/**
63 - * Notice how refs ownership is maintained even when injecting a component
64 - * into a different parent.
65 - */
66 -class TestRefsComponent extends React.Component {
67 - doReset = () => {
68 - this.refs.myCounter.triggerReset();
69 - };
70 -
71 - render() {
72 - return (
73 - <div>
74 - <div ref="resetDiv" onClick={this.doReset}>
75 - Reset Me By Clicking This.
76 - </div>
77 - <GeneralContainerComponent ref="myContainer">
78 - <ClickCounter ref="myCounter" initialCount={1} />
79 - </GeneralContainerComponent>
80 - </div>
81 - );
82 - }
83 -}
84 -
85 -const expectClickLogsLengthToBe = function(instance, length) {
86 - const clickLogs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
87 - instance,
88 - 'clickLogDiv',
89 - );
90 - expect(clickLogs.length).toBe(length);
91 - expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
92 -};
93 -
17 +// This is testing if string refs are deleted from `instance.refs`
18 +// Once support for string refs is removed, this test can be removed.
19 +// Detaching is already tested in refs-detruction-test.js
20 describe('reactiverefs', () => {
21 let container;
22
@@ -98,6 +24,7 @@ describe('reactiverefs', () => {
24 jest.resetModules();
25 React = require('react');
26 ReactDOM = require('react-dom');
27 + ReactFeatureFlags = require('shared/ReactFeatureFlags');
28 ReactTestUtils = require('react-dom/test-utils');
29 });
30
@@ -108,13 +35,117 @@ describe('reactiverefs', () => {
35 }
36 });
37
38 + /**
39 + * Counts clicks and has a renders an item for each click. Each item rendered
40 + * has a ref of the form "clickLogN".
41 + */
42 + class ClickCounter extends React.Component {
43 + state = {count: this.props.initialCount};
44 +
45 + triggerReset = () => {
46 + this.setState({count: this.props.initialCount});
47 + };
48 +
49 + handleClick = () => {
50 + this.setState({count: this.state.count + 1});
51 + };
52 +
53 + render() {
54 + const children = [];
55 + let i;
56 + for (i = 0; i < this.state.count; i++) {
57 + children.push(
58 + <div
59 + className="clickLogDiv"
60 + key={'clickLog' + i}
61 + ref={'clickLog' + i}
62 + />,
63 + );
64 + }
65 + return (
66 + <span className="clickIncrementer" onClick={this.handleClick}>
67 + {children}
68 + </span>
69 + );
70 + }
71 + }
72 +
73 + const expectClickLogsLengthToBe = function(instance, length) {
74 + const clickLogs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
75 + instance,
76 + 'clickLogDiv',
77 + );
78 + expect(clickLogs.length).toBe(length);
79 + expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
80 + };
81 +
82 /**
83 * Render a TestRefsComponent and ensure that the main refs are wired up.
84 */
85 const renderTestRefsComponent = function() {
86 + /**
87 + * Only purpose is to test that refs are tracked even when applied to a
88 + * component that is injected down several layers. Ref systems are difficult to
89 + * build in such a way that ownership is maintained in an airtight manner.
90 + */
91 + class GeneralContainerComponent extends React.Component {
92 + render() {
93 + return <div>{this.props.children}</div>;
94 + }
95 + }
96 +
97 + /**
98 + * Notice how refs ownership is maintained even when injecting a component
99 + * into a different parent.
100 + */
101 + class TestRefsComponent extends React.Component {
102 + doReset = () => {
103 + this.refs.myCounter.triggerReset();
104 + };
105 +
106 + render() {
107 + return (
108 + <div>
109 + <div ref="resetDiv" onClick={this.doReset}>
110 + Reset Me By Clicking This.
111 + </div>
112 + <GeneralContainerComponent ref="myContainer">
113 + <ClickCounter ref="myCounter" initialCount={1} />
114 + </GeneralContainerComponent>
115 + </div>
116 + );
117 + }
118 + }
119 +
120 container = document.createElement('div');
121 document.body.appendChild(container);
117 - const testRefsComponent = ReactDOM.render(<TestRefsComponent />, container);
122 +
123 + let testRefsComponent;
124 + expect(() => {
125 + testRefsComponent = ReactDOM.render(<TestRefsComponent />, container);
126 + }).toErrorDev(
127 + ReactFeatureFlags.warnAboutStringRefs
128 + ? [
129 + 'Warning: Component "div" contains the string ref "resetDiv". ' +
130 + 'Support for string refs will be removed in a future major release. ' +
131 + 'We recommend using useRef() or createRef() instead. ' +
132 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
133 + ' in div (at **)\n' +
134 + ' in TestRefsComponent (at **)',
135 + 'Warning: Component "span" contains the string ref "clickLog0". ' +
136 + 'Support for string refs will be removed in a future major release. ' +
137 + 'We recommend using useRef() or createRef() instead. ' +
138 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
139 + ' in span (at **)\n' +
140 + ' in ClickCounter (at **)\n' +
141 + ' in div (at **)\n' +
142 + ' in GeneralContainerComponent (at **)\n' +
143 + ' in div (at **)\n' +
144 + ' in TestRefsComponent (at **)',
145 + ]
146 + : [],
147 + );
148 +
149 expect(testRefsComponent instanceof TestRefsComponent).toBe(true);
150
151 const generalContainer = testRefsComponent.refs.myContainer;
@@ -156,13 +187,14 @@ describe('reactiverefs', () => {
187 });
188 });
189
159 -if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
190 +if (!ReactFeatureFlags.disableModulePatternComponents) {
191 describe('factory components', () => {
192 it('Should correctly get the ref', () => {
193 function Comp() {
194 return {
195 + elemRef: React.createRef(),
196 render() {
165 - return <div ref="elemRef" />;
197 + return <div ref={this.elemRef} />;
198 },
199 };
200 }
@@ -177,7 +209,7 @@ if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
209 '`Comp.prototype = React.Component.prototype`. ' +
210 "Don't use an arrow function since it cannot be called with `new` by React.",
211 );
180 - expect(inst.refs.elemRef.tagName).toBe('DIV');
212 + expect(inst.elemRef.current.tagName).toBe('DIV');
213 });
214 });
215 }
@@ -191,10 +223,15 @@ describe('ref swapping', () => {
223 jest.resetModules();
224 React = require('react');
225 ReactDOM = require('react-dom');
226 + ReactFeatureFlags = require('shared/ReactFeatureFlags');
227 ReactTestUtils = require('react-dom/test-utils');
228
229 RefHopsAround = class extends React.Component {
230 state = {count: 0};
231 + hopRef = React.createRef();
232 + divOneRef = React.createRef();
233 + divTwoRef = React.createRef();
234 + divThreeRef = React.createRef();
235
236 moveRef = () => {
237 this.setState({count: this.state.count + 1});
@@ -212,15 +249,15 @@ describe('ref swapping', () => {
249 <div>
250 <div
251 className="first"
215 - ref={count % 3 === 0 ? 'hopRef' : 'divOneRef'}
252 + ref={count % 3 === 0 ? this.hopRef : this.divOneRef}
253 />
254 <div
255 className="second"
219 - ref={count % 3 === 1 ? 'hopRef' : 'divTwoRef'}
256 + ref={count % 3 === 1 ? this.hopRef : this.divTwoRef}
257 />
258 <div
259 className="third"
223 - ref={count % 3 === 2 ? 'hopRef' : 'divThreeRef'}
260 + ref={count % 3 === 2 ? this.hopRef : this.divThreeRef}
261 />
262 </div>
263 );
@@ -244,28 +281,28 @@ describe('ref swapping', () => {
281 'third',
282 );
283
247 - expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
248 - expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
249 - expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
284 + expect(refHopsAround.hopRef.current).toEqual(firstDiv);
285 + expect(refHopsAround.divTwoRef.current).toEqual(secondDiv);
286 + expect(refHopsAround.divThreeRef.current).toEqual(thirdDiv);
287
288 refHopsAround.moveRef();
252 - expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
253 - expect(refHopsAround.refs.hopRef).toEqual(secondDiv);
254 - expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
289 + expect(refHopsAround.divOneRef.current).toEqual(firstDiv);
290 + expect(refHopsAround.hopRef.current).toEqual(secondDiv);
291 + expect(refHopsAround.divThreeRef.current).toEqual(thirdDiv);
292
293 refHopsAround.moveRef();
257 - expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
258 - expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
259 - expect(refHopsAround.refs.hopRef).toEqual(thirdDiv);
294 + expect(refHopsAround.divOneRef.current).toEqual(firstDiv);
295 + expect(refHopsAround.divTwoRef.current).toEqual(secondDiv);
296 + expect(refHopsAround.hopRef.current).toEqual(thirdDiv);
297
298 /**
299 * Make sure that after the third, we're back to where we started and the
300 * refs are completely restored.
301 */
302 refHopsAround.moveRef();
266 - expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
267 - expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
268 - expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
303 + expect(refHopsAround.hopRef.current).toEqual(firstDiv);
304 + expect(refHopsAround.divTwoRef.current).toEqual(secondDiv);
305 + expect(refHopsAround.divThreeRef.current).toEqual(thirdDiv);
306 });
307
308 it('always has a value for this.refs', () => {
@@ -309,7 +346,20 @@ describe('ref swapping', () => {
346 return <div ref={1} />;
347 }
348 }
312 - const a = ReactTestUtils.renderIntoDocument(<A />);
349 + let a;
350 + expect(() => {
351 + a = ReactTestUtils.renderIntoDocument(<A />);
352 + }).toErrorDev(
353 + ReactFeatureFlags.warnAboutStringRefs
354 + ? [
355 + 'Warning: Component "A" contains the string ref "1". ' +
356 + 'Support for string refs will be removed in a future major release. ' +
357 + 'We recommend using useRef() or createRef() instead. ' +
358 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
359 + ' in A (at **)',
360 + ]
361 + : [],
362 + );
363 expect(a.refs[1].nodeName).toBe('DIV');
364 });
365
@@ -464,7 +514,7 @@ describe('root level refs', () => {
514 });
515 });
516
467 -describe('creating element with ref in constructor', () => {
517 +describe('creating element with string ref in constructor', () => {
518 class RefTest extends React.Component {
519 constructor(props) {
520 super(props);
@@ -521,13 +571,41 @@ describe('strings refs across renderers', () => {
571
572 const div1 = document.createElement('div');
573 const div2 = document.createElement('div');
524 - const inst = ReactDOM.render(<Parent />, div1);
574 +
575 + let inst;
576 + expect(() => {
577 + inst = ReactDOM.render(<Parent />, div1);
578 + }).toErrorDev(
579 + ReactFeatureFlags.warnAboutStringRefs
580 + ? [
581 + 'Warning: Component "Indirection" contains the string ref "child1". ' +
582 + 'Support for string refs will be removed in a future major release. ' +
583 + 'We recommend using useRef() or createRef() instead. ' +
584 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
585 + ' in Indirection (at **)\n' +
586 + ' in Parent (at **)',
587 + ]
588 + : [],
589 + );
590 +
591 // Only the first ref has rendered yet.
592 expect(inst.refs.child1.tagName).toBe('DIV');
593 expect(inst.refs.child1).toBe(div1.firstChild);
594
529 - // Now both refs should be rendered.
530 - ReactDOM.render(<Parent />, div1);
595 + expect(() => {
596 + // Now both refs should be rendered.
597 + ReactDOM.render(<Parent />, div1);
598 + }).toErrorDev(
599 + ReactFeatureFlags.warnAboutStringRefs
600 + ? [
601 + 'Warning: Component "Root" contains the string ref "child2". ' +
602 + 'Support for string refs will be removed in a future major release. ' +
603 + 'We recommend using useRef() or createRef() instead. ' +
604 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref',
605 + ]
606 + : [],
607 + {withoutStack: true},
608 + );
609 expect(inst.refs.child1.tagName).toBe('DIV');
610 expect(inst.refs.child1).toBe(div1.firstChild);
611 expect(inst.refs.child2.tagName).toBe('DIV');
packages/react-native-renderer/src/__tests__/ResponderEventPlugin-test.internal.js
+42 -27
@@ -1385,25 +1385,36 @@ describe('ResponderEventPlugin', () => {
1385 const ReactDOMComponentTree = require('react-dom-bindings/src/client/ReactDOMComponentTree');
1386
1387 class ChildComponent extends React.Component {
1388 + divRef = React.createRef();
1389 + div1Ref = React.createRef();
1390 + div2Ref = React.createRef();
1391 +
1392 render() {
1393 return (
1390 - <div ref="DIV" id={this.props.id + '__DIV'}>
1391 - <div ref="DIV_1" id={this.props.id + '__DIV_1'} />
1392 - <div ref="DIV_2" id={this.props.id + '__DIV_2'} />
1394 + <div ref={this.divRef} id={this.props.id + '__DIV'}>
1395 + <div ref={this.div1Ref} id={this.props.id + '__DIV_1'} />
1396 + <div ref={this.div2Ref} id={this.props.id + '__DIV_2'} />
1397 </div>
1398 );
1399 }
1400 }
1401
1402 class ParentComponent extends React.Component {
1403 + pRef = React.createRef();
1404 + p_P1Ref = React.createRef();
1405 + p_P1Ref = React.createRef();
1406 + p_P1_C1Ref = React.createRef();
1407 + p_P1_C2Ref = React.createRef();
1408 + p_OneOffRef = React.createRef();
1409 +
1410 render() {
1411 return (
1401 - <div ref="P" id="P">
1402 - <div ref="P_P1" id="P_P1">
1403 - <ChildComponent ref="P_P1_C1" id="P_P1_C1" />
1404 - <ChildComponent ref="P_P1_C2" id="P_P1_C2" />
1412 + <div ref={this.pRef} id="P">
1413 + <div ref={this.p_P1Ref} id="P_P1">
1414 + <ChildComponent ref={this.p_P1_C1Ref} id="P_P1_C1" />
1415 + <ChildComponent ref={this.p_P1_C2Ref} id="P_P1_C2" />
1416 </div>
1406 - <div ref="P_OneOff" id="P_OneOff" />
1417 + <div ref={this.p_OneOffRef} id="P_OneOff" />
1418 </div>
1419 );
1420 }
@@ -1414,41 +1425,45 @@ describe('ResponderEventPlugin', () => {
1425 const ancestors = [
1426 // Common ancestor with self is self.
1427 {
1417 - one: parent.refs.P_P1_C1.refs.DIV_1,
1418 - two: parent.refs.P_P1_C1.refs.DIV_1,
1419 - com: parent.refs.P_P1_C1.refs.DIV_1,
1428 + one: parent.p_P1_C1Ref.current.div1Ref.current,
1429 + two: parent.p_P1_C1Ref.current.div1Ref.current,
1430 + com: parent.p_P1_C1Ref.current.div1Ref.current,
1431 },
1432 // Common ancestor with self is self - even if topmost DOM.
1422 - {one: parent.refs.P, two: parent.refs.P, com: parent.refs.P},
1433 + {
1434 + one: parent.pRef.current,
1435 + two: parent.pRef.current,
1436 + com: parent.pRef.current,
1437 + },
1438 // Siblings
1439 {
1425 - one: parent.refs.P_P1_C1.refs.DIV_1,
1426 - two: parent.refs.P_P1_C1.refs.DIV_2,
1427 - com: parent.refs.P_P1_C1.refs.DIV,
1440 + one: parent.p_P1_C1Ref.current.div1Ref.current,
1441 + two: parent.p_P1_C1Ref.current.div2Ref.current,
1442 + com: parent.p_P1_C1Ref.current.divRef.current,
1443 },
1444 // Common ancestor with parent is the parent.
1445 {
1431 - one: parent.refs.P_P1_C1.refs.DIV_1,
1432 - two: parent.refs.P_P1_C1.refs.DIV,
1433 - com: parent.refs.P_P1_C1.refs.DIV,
1446 + one: parent.p_P1_C1Ref.current.div1Ref.current,
1447 + two: parent.p_P1_C1Ref.current.divRef.current,
1448 + com: parent.p_P1_C1Ref.current.divRef.current,
1449 },
1450 // Common ancestor with grandparent is the grandparent.
1451 {
1437 - one: parent.refs.P_P1_C1.refs.DIV_1,
1438 - two: parent.refs.P_P1,
1439 - com: parent.refs.P_P1,
1452 + one: parent.p_P1_C1Ref.current.div1Ref.current,
1453 + two: parent.p_P1Ref.current,
1454 + com: parent.p_P1Ref.current,
1455 },
1456 // Grandparent across subcomponent boundaries.
1457 {
1443 - one: parent.refs.P_P1_C1.refs.DIV_1,
1444 - two: parent.refs.P_P1_C2.refs.DIV_1,
1445 - com: parent.refs.P_P1,
1458 + one: parent.p_P1_C1Ref.current.div1Ref.current,
1459 + two: parent.p_P1_C2Ref.current.div1Ref.current,
1460 + com: parent.p_P1Ref.current,
1461 },
1462 // Something deep with something one-off.
1463 {
1449 - one: parent.refs.P_P1_C1.refs.DIV_1,
1450 - two: parent.refs.P_OneOff,
1451 - com: parent.refs.P,
1464 + one: parent.p_P1_C1Ref.current.div1Ref.current,
1465 + two: parent.p_OneOffRef.current,
1466 + com: parent.pRef.current,
1467 },
1468 ];
1469 let i;
packages/react-reconciler/src/ReactChildFiber.new.js
+14 -1
@@ -97,6 +97,10 @@ if (__DEV__) {
97 };
98 }
99
100 +function isReactClass(type) {
101 + return type.prototype && type.prototype.isReactComponent;
102 +}
103 +
104 function coerceRef(
105 returnFiber: Fiber,
106 current: Fiber | null,
@@ -120,7 +124,16 @@ function coerceRef(
124 element._owner &&
125 element._self &&
126 element._owner.stateNode !== element._self
123 - )
127 + ) &&
128 + // Will already throw with "Function components cannot have string refs"
129 + !(
130 + element._owner &&
131 + ((element._owner: any): Fiber).tag !== ClassComponent
132 + ) &&
133 + // Will already warn with "Function components cannot be given refs"
134 + !(typeof element.type === 'function' && !isReactClass(element.type)) &&
135 + // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set"
136 + element._owner
137 ) {
138 const componentName =
139 getComponentNameFromFiber(returnFiber) || 'Component';
packages/react-reconciler/src/ReactChildFiber.old.js
+14 -1
@@ -97,6 +97,10 @@ if (__DEV__) {
97 };
98 }
99
100 +function isReactClass(type) {
101 + return type.prototype && type.prototype.isReactComponent;
102 +}
103 +
104 function coerceRef(
105 returnFiber: Fiber,
106 current: Fiber | null,
@@ -120,7 +124,16 @@ function coerceRef(
124 element._owner &&
125 element._self &&
126 element._owner.stateNode !== element._self
123 - )
127 + ) &&
128 + // Will already throw with "Function components cannot have string refs"
129 + !(
130 + element._owner &&
131 + ((element._owner: any): Fiber).tag !== ClassComponent
132 + ) &&
133 + // Will already warn with "Function components cannot be given refs"
134 + !(typeof element.type === 'function' && !isReactClass(element.type)) &&
135 + // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set"
136 + element._owner
137 ) {
138 const componentName =
139 getComponentNameFromFiber(returnFiber) || 'Component';
packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js
+15 -2
@@ -11,6 +11,7 @@
11 'use strict';
12
13 let React;
14 +let ReactFeatureFlags;
15 let ReactNoop;
16 let Scheduler;
17
@@ -19,6 +20,7 @@ describe('ReactIncrementalSideEffects', () => {
20 jest.resetModules();
21
22 React = require('react');
23 + ReactFeatureFlags = require('shared/ReactFeatureFlags');
24 ReactNoop = require('react-noop-renderer');
25 Scheduler = require('scheduler');
26 });
@@ -1306,8 +1308,19 @@ describe('ReactIncrementalSideEffects', () => {
1308 }
1309
1310 ReactNoop.render(<Foo />);
1309 - expect(Scheduler).toFlushWithoutYielding();
1310 -
1311 + expect(() => {
1312 + expect(Scheduler).toFlushWithoutYielding();
1313 + }).toErrorDev(
1314 + ReactFeatureFlags.warnAboutStringRefs
1315 + ? [
1316 + 'Warning: Component "Foo" contains the string ref "bar". ' +
1317 + 'Support for string refs will be removed in a future major release. ' +
1318 + 'We recommend using useRef() or createRef() instead. ' +
1319 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
1320 + ' in Foo (at **)',
1321 + ]
1322 + : [],
1323 + );
1324 expect(fooInstance.refs.bar.test).toEqual('test');
1325 });
1326 });
packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js
+13 -6
@@ -271,13 +271,15 @@ describe('ReactTestRenderer', () => {
271 return <div>Hello, world</div>;
272 }
273 class Foo extends React.Component {
274 + fooRef = React.createRef();
275 render() {
275 - return <Bar ref="foo" />;
276 + return <Bar ref={this.fooRef} />;
277 }
278 }
279 class Baz extends React.Component {
280 + bazRef = React.createRef();
281 render() {
280 - return <div ref="baz" />;
282 + return <div ref={this.bazRef} />;
283 }
284 }
285 ReactTestRenderer.create(<Baz />);
@@ -298,11 +300,12 @@ describe('ReactTestRenderer', () => {
300 const mockAnchorInstance = {hover: () => {}};
301 const log = [];
302 class Foo extends React.Component {
303 + barRef = React.createRef();
304 componentDidMount() {
302 - log.push(this.refs.bar);
305 + log.push(this.barRef.current);
306 }
307 render() {
305 - return <a ref="bar">Hello, world</a>;
308 + return <a ref={this.barRef}>Hello, world</a>;
309 }
310 }
311 function createNodeMock(element) {
@@ -355,7 +358,7 @@ describe('ReactTestRenderer', () => {
358 it('supports unmounting when using refs', () => {
359 class Foo extends React.Component {
360 render() {
358 - return <div ref="foo" />;
361 + return <div ref={React.createRef()} />;
362 }
363 }
364 const inst = ReactTestRenderer.create(<Foo />, {
@@ -394,7 +397,11 @@ describe('ReactTestRenderer', () => {
397 };
398 class Foo extends React.Component {
399 render() {
397 - return this.props.useDiv ? <div ref="foo" /> : <span ref="foo" />;
400 + return this.props.useDiv ? (
401 + <div ref={React.createRef()} />
402 + ) : (
403 + <span ref={React.createRef()} />
404 + );
405 }
406 }
407 const inst = ReactTestRenderer.create(<Foo useDiv={true} />, {
packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee
+16 -2
@@ -9,6 +9,7 @@ PropTypes = null
9 React = null
10 ReactDOM = null
11 ReactDOMClient = null
12 +ReactFeatureFlags = null
13 act = null
14
15 describe 'ReactCoffeeScriptClass', ->
@@ -22,6 +23,7 @@ describe 'ReactCoffeeScriptClass', ->
23 React = require 'react'
24 ReactDOM = require 'react-dom'
25 ReactDOMClient = require 'react-dom/client'
26 + ReactFeatureFlags = require 'shared/ReactFeatureFlags'
27 act = require('jest-react').act
28 PropTypes = require 'prop-types'
29 container = document.createElement 'div'
@@ -528,7 +530,7 @@ describe 'ReactCoffeeScriptClass', ->
530
531 test React.createElement(Foo), 'DIV', 'bar-through-context'
532
531 - it 'supports classic refs', ->
533 + it 'supports string refs', ->
534 class Foo extends React.Component
535 render: ->
536 React.createElement(InnerComponent,
@@ -537,7 +539,19 @@ describe 'ReactCoffeeScriptClass', ->
539 )
540
541 ref = React.createRef()
540 - test(React.createElement(Foo, ref: ref), 'DIV', 'foo')
542 + expect(->
543 + test(React.createElement(Foo, ref: ref), 'DIV', 'foo')
544 + ).toErrorDev(
545 + if ReactFeatureFlags.warnAboutStringRefs
546 + then [
547 + 'Warning: Component "Foo" contains the string ref "inner". ' +
548 + 'Support for string refs will be removed in a future major release. ' +
549 + 'We recommend using useRef() or createRef() instead. ' +
550 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
551 + ' in Foo (at **)'
552 + ]
553 + else []
554 + );
555 expect(ref.current.refs.inner.getName()).toBe 'foo'
556
557 it 'supports drilling through to the DOM using findDOMNode', ->
packages/react/src/__tests__/ReactContextValidator-test.js
+4 -2
@@ -46,6 +46,8 @@ describe('ReactContextValidator', () => {
46 };
47
48 class ComponentInFooBarContext extends React.Component {
49 + childRef = React.createRef();
50 +
51 getChildContext() {
52 return {
53 foo: 'abc',
@@ -54,7 +56,7 @@ describe('ReactContextValidator', () => {
56 }
57
58 render() {
57 - return <Component ref="child" />;
59 + return <Component ref={this.childRef} />;
60 }
61 }
62 ComponentInFooBarContext.childContextTypes = {
@@ -65,7 +67,7 @@ describe('ReactContextValidator', () => {
67 const instance = ReactTestUtils.renderIntoDocument(
68 <ComponentInFooBarContext />,
69 );
68 - expect(instance.refs.child.context).toEqual({foo: 'abc'});
70 + expect(instance.childRef.current.context).toEqual({foo: 'abc'});
71 });
72
73 it('should pass next context to lifecycles', () => {
packages/react/src/__tests__/ReactES6Class-test.js
+16 -2
@@ -13,6 +13,7 @@ let PropTypes;
13 let React;
14 let ReactDOM;
15 let ReactDOMClient;
16 +let ReactFeatureFlags;
17 let act;
18
19 describe('ReactES6Class', () => {
@@ -31,6 +32,7 @@ describe('ReactES6Class', () => {
32 React = require('react');
33 ReactDOM = require('react-dom');
34 ReactDOMClient = require('react-dom/client');
35 + ReactFeatureFlags = require('shared/ReactFeatureFlags');
36 act = require('jest-react').act;
37 container = document.createElement('div');
38 root = ReactDOMClient.createRoot(container);
@@ -568,14 +570,26 @@ describe('ReactES6Class', () => {
570 test(<Foo />, 'DIV', 'bar-through-context');
571 });
572
571 - it('supports classic refs', () => {
573 + it('supports string refs', () => {
574 class Foo extends React.Component {
575 render() {
576 return <Inner name="foo" ref="inner" />;
577 }
578 }
579 const ref = React.createRef();
578 - test(<Foo ref={ref} />, 'DIV', 'foo');
580 + expect(() => {
581 + test(<Foo ref={ref} />, 'DIV', 'foo');
582 + }).toErrorDev(
583 + ReactFeatureFlags.warnAboutStringRefs
584 + ? [
585 + 'Warning: Component "Foo" contains the string ref "inner". ' +
586 + 'Support for string refs will be removed in a future major release. ' +
587 + 'We recommend using useRef() or createRef() instead. ' +
588 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
589 + ' in Foo (at **)',
590 + ]
591 + : [],
592 + );
593 expect(ref.current.refs.inner.getName()).toBe('foo');
594 });
595
packages/react/src/__tests__/ReactElement-test.js
+1 -1
@@ -93,7 +93,7 @@ describe('ReactElement', () => {
93 render() {
94 return (
95 <div>
96 - <Child ref="childElement" />
96 + <Child ref={React.createRef()} />
97 </div>
98 );
99 }
packages/react/src/__tests__/ReactElementClone-test.js
+24 -11
@@ -82,8 +82,10 @@ describe('ReactElementClone', () => {
82
83 it('should keep the original ref if it is not overridden', () => {
84 class Grandparent extends React.Component {
85 + yoloRef = React.createRef();
86 +
87 render() {
86 - return <Parent child={<div ref="yolo" />} />;
88 + return <Parent child={<div ref={this.yoloRef} />} />;
89 }
90 }
91
@@ -96,7 +98,7 @@ describe('ReactElementClone', () => {
98 }
99
100 const component = ReactTestUtils.renderIntoDocument(<Grandparent />);
99 - expect(component.refs.yolo.tagName).toBe('DIV');
101 + expect(component.yoloRef.current.tagName).toBe('DIV');
102 });
103
104 it('should transfer the key property', () => {
@@ -174,21 +176,25 @@ describe('ReactElementClone', () => {
176
177 it('should support keys and refs', () => {
178 class Parent extends React.Component {
179 + xyzRef = React.createRef();
180 +
181 render() {
182 const clone = React.cloneElement(this.props.children, {
183 key: 'xyz',
180 - ref: 'xyz',
184 + ref: this.xyzRef,
185 });
186 expect(clone.key).toBe('xyz');
183 - expect(clone.ref).toBe('xyz');
187 + expect(clone.ref).toBe(this.xyzRef);
188 return <div>{clone}</div>;
189 }
190 }
191
192 class Grandparent extends React.Component {
193 + parentRef = React.createRef();
194 +
195 render() {
196 return (
191 - <Parent ref="parent">
197 + <Parent ref={this.parentRef}>
198 <span key="abc" />
199 </Parent>
200 );
@@ -196,30 +202,37 @@ describe('ReactElementClone', () => {
202 }
203
204 const component = ReactTestUtils.renderIntoDocument(<Grandparent />);
199 - expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
205 + expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN');
206 });
207
208 it('should steal the ref if a new ref is specified', () => {
209 class Parent extends React.Component {
210 + xyzRef = React.createRef();
211 +
212 render() {
205 - const clone = React.cloneElement(this.props.children, {ref: 'xyz'});
213 + const clone = React.cloneElement(this.props.children, {
214 + ref: this.xyzRef,
215 + });
216 return <div>{clone}</div>;
217 }
218 }
219
220 class Grandparent extends React.Component {
221 + parentRef = React.createRef();
222 + childRef = React.createRef();
223 +
224 render() {
225 return (
213 - <Parent ref="parent">
214 - <span ref="child" />
226 + <Parent ref={this.parentRef}>
227 + <span ref={this.childRef} />
228 </Parent>
229 );
230 }
231 }
232
233 const component = ReactTestUtils.renderIntoDocument(<Grandparent />);
221 - expect(component.refs.child).toBeUndefined();
222 - expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
234 + expect(component.childRef).toEqual({current: null});
235 + expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN');
236 });
237
238 it('should overwrite props', () => {
packages/react/src/__tests__/ReactElementJSX-test.js
+1 -1
@@ -221,7 +221,7 @@ describe('ReactElement.jsx', () => {
221 class Parent extends React.Component {
222 render() {
223 return JSXRuntime.jsx('div', {
224 - children: JSXRuntime.jsx(Child, {ref: 'childElement'}),
224 + children: JSXRuntime.jsx(Child, {ref: React.createRef()}),
225 });
226 }
227 }
packages/react/src/__tests__/ReactJSXElement-test.js
+3 -2
@@ -78,10 +78,11 @@ describe('ReactJSXElement', () => {
78 });
79
80 it('extracts key and ref from the rest of the props', () => {
81 - const element = <Component key="12" ref="34" foo="56" />;
81 + const ref = React.createRef();
82 + const element = <Component key="12" ref={ref} foo="56" />;
83 expect(element.type).toBe(Component);
84 expect(element.key).toBe('12');
84 - expect(element.ref).toBe('34');
85 + expect(element.ref).toBe(ref);
86 const expectation = {foo: '56'};
87 Object.freeze(expectation);
88 expect(element.props).toEqual(expectation);
packages/react/src/__tests__/ReactStrictMode-test.js
+26 -13
@@ -926,12 +926,18 @@ describe('string refs', () => {
926 expect(() => {
927 ReactDOM.render(<OuterComponent />, container);
928 }).toErrorDev(
929 - 'Warning: A string ref, "somestring", has been found within a strict mode tree. ' +
930 - 'String refs are a source of potential bugs and should be avoided. ' +
931 - 'We recommend using useRef() or createRef() instead. ' +
932 - 'Learn more about using refs safely here: ' +
933 - 'https://reactjs.org/link/strict-mode-string-ref\n' +
934 - ' in OuterComponent (at **)',
929 + ReactFeatureFlags.warnAboutStringRefs
930 + ? 'Warning: Component "StrictMode" contains the string ref "somestring". ' +
931 + 'Support for string refs will be removed in a future major release. ' +
932 + 'We recommend using useRef() or createRef() instead. ' +
933 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
934 + ' in OuterComponent (at **)'
935 + : 'Warning: A string ref, "somestring", has been found within a strict mode tree. ' +
936 + 'String refs are a source of potential bugs and should be avoided. ' +
937 + 'We recommend using useRef() or createRef() instead. ' +
938 + 'Learn more about using refs safely here: ' +
939 + 'https://reactjs.org/link/strict-mode-string-ref\n' +
940 + ' in OuterComponent (at **)',
941 );
942
943 // Dedup
@@ -967,13 +973,20 @@ describe('string refs', () => {
973 expect(() => {
974 ReactDOM.render(<OuterComponent />, container);
975 }).toErrorDev(
970 - 'Warning: A string ref, "somestring", has been found within a strict mode tree. ' +
971 - 'String refs are a source of potential bugs and should be avoided. ' +
972 - 'We recommend using useRef() or createRef() instead. ' +
973 - 'Learn more about using refs safely here: ' +
974 - 'https://reactjs.org/link/strict-mode-string-ref\n' +
975 - ' in InnerComponent (at **)\n' +
976 - ' in OuterComponent (at **)',
976 + ReactFeatureFlags.warnAboutStringRefs
977 + ? 'Warning: Component "InnerComponent" contains the string ref "somestring". ' +
978 + 'Support for string refs will be removed in a future major release. ' +
979 + 'We recommend using useRef() or createRef() instead. ' +
980 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
981 + ' in InnerComponent (at **)\n' +
982 + ' in OuterComponent (at **)'
983 + : 'Warning: A string ref, "somestring", has been found within a strict mode tree. ' +
984 + 'String refs are a source of potential bugs and should be avoided. ' +
985 + 'We recommend using useRef() or createRef() instead. ' +
986 + 'Learn more about using refs safely here: ' +
987 + 'https://reactjs.org/link/strict-mode-string-ref\n' +
988 + ' in InnerComponent (at **)\n' +
989 + ' in OuterComponent (at **)',
990 );
991
992 // Dedup
packages/react/src/__tests__/ReactTypeScriptClass-test.ts
+15 -2
@@ -17,6 +17,7 @@ import ReactDOMClient = require('react-dom/client');
17 import ReactDOMTestUtils = require('react-dom/test-utils');
18 import PropTypes = require('prop-types');
19 import internalAct = require('jest-react');
20 +import ReactFeatureFlags = require('shared/ReactFeatureFlags')
21
22 // Before Each
23
@@ -686,9 +687,21 @@ describe('ReactTypeScriptClass', function() {
687 test(React.createElement(ProvideContext), 'DIV', 'bar-through-context');
688 });
689
689 - it('supports classic refs', function() {
690 + it('supports string refs', function() {
691 const ref = React.createRef();
691 - test(React.createElement(ClassicRefs, {ref: ref}), 'DIV', 'foo');
692 + expect(() => {
693 + test(React.createElement(ClassicRefs, {ref: ref}), 'DIV', 'foo');
694 + }).toErrorDev(
695 + ReactFeatureFlags.warnAboutStringRefs
696 + ? [
697 + 'Warning: Component "ClassicRefs" contains the string ref "inner". ' +
698 + 'Support for string refs will be removed in a future major release. ' +
699 + 'We recommend using useRef() or createRef() instead. ' +
700 + 'Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref\n' +
701 + ' in ClassicRefs (at **)',
702 + ]
703 + : [],
704 + );
705 expect(ref.current.refs.inner.getName()).toBe('foo');
706 });
707
packages/shared/ReactFeatureFlags.js
+1 -1
@@ -219,7 +219,7 @@ export const warnAboutDefaultPropsOnFunctionComponents = false; // deprecate lat
219 // a deprecated pattern we want to get rid of in the future
220 export const warnAboutSpreadingKeyToJSX = true;
221
222 -export const warnAboutStringRefs = false;
222 +export const warnAboutStringRefs = true;
223
224 // -----------------------------------------------------------------------------
225 // Debugging and DevTools
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1 -1
@@ -42,7 +42,7 @@ export const enableScopeAPI = false;
42 export const enableCreateEventHandleAPI = false;
43 export const enableSuspenseCallback = false;
44 export const warnAboutDefaultPropsOnFunctionComponents = false;
45 -export const warnAboutStringRefs = false;
45 +export const warnAboutStringRefs = true;
46 export const disableLegacyContext = false;
47 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
48 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1 -1
@@ -32,7 +32,7 @@ export const enableScopeAPI = false;
32 export const enableCreateEventHandleAPI = false;
33 export const enableSuspenseCallback = false;
34 export const warnAboutDefaultPropsOnFunctionComponents = false;
35 -export const warnAboutStringRefs = false;
35 +export const warnAboutStringRefs = true;
36 export const disableLegacyContext = false;
37 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
38 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1 -1
@@ -32,7 +32,7 @@ export const enableScopeAPI = false;
32 export const enableCreateEventHandleAPI = false;
33 export const enableSuspenseCallback = false;
34 export const warnAboutDefaultPropsOnFunctionComponents = false;
35 -export const warnAboutStringRefs = false;
35 +export const warnAboutStringRefs = true;
36 export const disableLegacyContext = false;
37 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
38 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
+1 -1
@@ -32,7 +32,7 @@ export const enableScopeAPI = false;
32 export const enableCreateEventHandleAPI = false;
33 export const enableSuspenseCallback = false;
34 export const warnAboutDefaultPropsOnFunctionComponents = false;
35 -export const warnAboutStringRefs = false;
35 +export const warnAboutStringRefs = true;
36 export const disableLegacyContext = false;
37 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
38 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1 -1
@@ -32,7 +32,7 @@ export const enableScopeAPI = true;
32 export const enableCreateEventHandleAPI = false;
33 export const enableSuspenseCallback = true;
34 export const warnAboutDefaultPropsOnFunctionComponents = false;
35 -export const warnAboutStringRefs = false;
35 +export const warnAboutStringRefs = true;
36 export const disableLegacyContext = false;
37 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
38 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.testing.js
+1 -1
@@ -32,7 +32,7 @@ export const enableScopeAPI = false;
32 export const enableCreateEventHandleAPI = false;
33 export const enableSuspenseCallback = false;
34 export const warnAboutDefaultPropsOnFunctionComponents = false;
35 -export const warnAboutStringRefs = false;
35 +export const warnAboutStringRefs = true;
36 export const disableLegacyContext = false;
37 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
38 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.testing.www.js
+1 -1
@@ -32,7 +32,7 @@ export const enableScopeAPI = true;
32 export const enableCreateEventHandleAPI = true;
33 export const enableSuspenseCallback = true;
34 export const warnAboutDefaultPropsOnFunctionComponents = false;
35 -export const warnAboutStringRefs = false;
35 +export const warnAboutStringRefs = true;
36 export const disableLegacyContext = __EXPERIMENTAL__;
37 export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
38 export const enableTrustedTypesIntegration = false;
packages/shared/forks/ReactFeatureFlags.www.js
+1 -1
@@ -66,7 +66,7 @@ export const enableSchedulingProfiler: boolean =
66 export const enableSchedulerDebugging = true;
67 export const warnAboutDeprecatedLifecycles = true;
68 export const disableLegacyContext = __EXPERIMENTAL__;
69 -export const warnAboutStringRefs = false;
69 +export const warnAboutStringRefs = true;
70 export const warnAboutDefaultPropsOnFunctionComponents = false;
71 export const enableGetInspectorDataForInstanceInProduction = false;
72