Unrevert "Support writing to this.refs from userspace" (#28879)
Reverts facebook/react#28877 We found the cause of the regression and should be able to land this again.
Jan Kassens committed
Apr 24, 2024 at 10:03 UTC
b039be627dd7403d7d2f63a48c8d263d955ce456
3 files changed
+35
-11
packages/react-reconciler/src/ReactFiberClassComponent.js
+9
-3
@@ -19,12 +19,13 @@ import {
19
} from './ReactFiberFlags';
20
import {
21
debugRenderPhaseSideEffectsForStrictMode,
22
+ disableDefaultPropsExceptForClasses,
23
disableLegacyContext,
24
+ disableStringRefs,
25
enableDebugTracing,
24
- enableSchedulingProfiler,
26
enableLazyContextPropagation,
27
enableRefAsProp,
27
- disableDefaultPropsExceptForClasses,
28
+ enableSchedulingProfiler,
29
} from 'shared/ReactFeatureFlags';
30
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
31
import {isMounted} from './ReactFiberTreeReflection';
@@ -819,7 +820,12 @@ function mountClassInstance(
820
const instance = workInProgress.stateNode;
821
instance.props = newProps;
822
instance.state = workInProgress.memoizedState;
822
- instance.refs = {};
823
+ if (!disableStringRefs) {
824
+ // When string refs are used in create-react-class legacy components,
825
+ // we need to make refs writable unless we patch all such copies of the
826
+ // class code that sets to a frozen emptyObject.
827
+ instance.refs = {};
828
+ }
829
830
initializeUpdateQueue(workInProgress);
831
packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js
+24
@@ -138,4 +138,28 @@ describe('ReactFiberRefs', () => {
138
);
139
expect(refProp).toBe('child');
140
});
141
+
142
+ test('strings refs can be codemodded to callback refs', async () => {
143
+ let app;
144
+ class App extends React.Component {
145
+ render() {
146
+ app = this;
147
+ return (
148
+ <div
149
+ prop="Hello!"
150
+ ref={el => {
151
+ // `refs` used to be a shared frozen object unless/until a string
152
+ // ref attached by the reconciler, but it's not anymore so that we
153
+ // can codemod string refs to userspace callback refs.
154
+ this.refs.div = el;
155
+ }}
156
+ />
157
+ );
158
+ }
159
+ }
160
+
161
+ const root = ReactNoop.createRoot();
162
+ await act(() => root.render(<App />));
163
+ expect(app.refs.div.prop).toBe('Hello!');
164
+ });
165
});
packages/react/src/ReactBaseClasses.js
+2
-8
@@ -8,19 +8,13 @@
8
import ReactNoopUpdateQueue from './ReactNoopUpdateQueue';
9
import assign from 'shared/assign';
10
11
-const emptyObject = {};
12
-if (__DEV__) {
13
- Object.freeze(emptyObject);
14
-}
15
-
11
/**
12
* Base class helpers for the updating state of a component.
13
*/
14
function Component(props, context, updater) {
15
this.props = props;
16
this.context = context;
22
- // If a component has string refs, we will assign a different object later.
23
- this.refs = emptyObject;
17
+ this.refs = {};
18
// We initialize the default updater but the real one gets injected by the
19
// renderer.
20
this.updater = updater || ReactNoopUpdateQueue;
@@ -133,7 +127,7 @@ function PureComponent(props, context, updater) {
127
this.props = props;
128
this.context = context;
129
// If a component has string refs, we will assign a different object later.
136
- this.refs = emptyObject;
130
+ this.refs = {};
131
this.updater = updater || ReactNoopUpdateQueue;
132
}
133