Skip to content

Commit 5636fad

Browse files
authored
[string-refs] log string ref from prod (#31161)
If passed as a feature flag, this calls the configured function when a string ref is used even from prod code to find the last usages.
1 parent 7b7fac0 commit 5636fad

9 files changed

+55
-20
lines changed

packages/react/src/jsx/ReactJSXElement.js

+17-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
disableStringRefs,
2525
disableDefaultPropsExceptForClasses,
2626
enableOwnerStacks,
27+
enableLogStringRefsProd,
2728
} from 'shared/ReactFeatureFlags';
2829
import {checkPropStringCoercion} from 'shared/CheckStringCoercion';
2930
import {ClassComponent} from 'react-reconciler/src/ReactWorkTags';
@@ -76,7 +77,7 @@ let didWarnAboutStringRefs;
7677
let didWarnAboutElementRef;
7778
let didWarnAboutOldJSXRuntime;
7879

79-
if (__DEV__) {
80+
if (__DEV__ || enableLogStringRefsProd) {
8081
didWarnAboutStringRefs = {};
8182
didWarnAboutElementRef = {};
8283
}
@@ -1314,22 +1315,27 @@ function stringRefAsCallbackRef(stringRef, type, owner, value) {
13141315
);
13151316
}
13161317

1317-
if (__DEV__) {
1318+
if (__DEV__ || enableLogStringRefsProd) {
13181319
if (
13191320
// Will already warn with "Function components cannot be given refs"
13201321
!(typeof type === 'function' && !isReactClass(type))
13211322
) {
13221323
const componentName = getComponentNameFromFiber(owner) || 'Component';
13231324
if (!didWarnAboutStringRefs[componentName]) {
1324-
console.error(
1325-
'Component "%s" contains the string ref "%s". Support for string refs ' +
1326-
'will be removed in a future major release. We recommend using ' +
1327-
'useRef() or createRef() instead. ' +
1328-
'Learn more about using refs safely here: ' +
1329-
'https://react.dev/link/strict-mode-string-ref',
1330-
componentName,
1331-
stringRef,
1332-
);
1325+
if (enableLogStringRefsProd) {
1326+
enableLogStringRefsProd(componentName, stringRef);
1327+
}
1328+
if (__DEV__) {
1329+
console.error(
1330+
'Component "%s" contains the string ref "%s". Support for string refs ' +
1331+
'will be removed in a future major release. We recommend using ' +
1332+
'useRef() or createRef() instead. ' +
1333+
'Learn more about using refs safely here: ' +
1334+
'https://react.dev/link/strict-mode-string-ref',
1335+
componentName,
1336+
stringRef,
1337+
);
1338+
}
13331339
didWarnAboutStringRefs[componentName] = true;
13341340
}
13351341
}

packages/shared/ReactFeatureFlags.js

+7
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ export const disableClientCache = true;
215215
// during element creation.
216216
export const enableRefAsProp = true;
217217
export const disableStringRefs = true;
218+
/**
219+
* If set to a function, the function will be called with the component name
220+
* and ref string.
221+
*
222+
* NOTE: This happens also in the production build.
223+
*/
224+
export const enableLogStringRefsProd: null | ((string, string) => void) = null;
218225

219226
// Warn on any usage of ReactTestRenderer
220227
export const enableReactTestRendererWarning = true;

packages/shared/forks/ReactFeatureFlags.native-fb.js

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export const enableLazyContextPropagation = true;
6565
export const enableLegacyCache = false;
6666
export const enableLegacyFBSupport = false;
6767
export const enableLegacyHidden = false;
68+
export const enableLogStringRefsProd: null | ((string, string) => void) = null;
6869
export const enableNoCloningMemoCache = false;
6970
export const enableOwnerStacks = false;
7071
export const enablePostpone = false;

packages/shared/forks/ReactFeatureFlags.native-oss.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const enableContextProfiling = false;
5656
export const enableLegacyCache = false;
5757
export const enableLegacyFBSupport = false;
5858
export const enableLegacyHidden = false;
59+
export const enableLogStringRefsProd: null | ((string, string) => void) = null;
5960
export const enableNoCloningMemoCache = false;
6061
export const enableObjectFiber = false;
6162
export const enableOwnerStacks = false;

packages/shared/forks/ReactFeatureFlags.test-renderer.js

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const enableUseEffectEventHook = false;
4444
export const favorSafetyOverHydrationPerf = true;
4545
export const enableComponentStackLocations = true;
4646
export const enableLegacyFBSupport = false;
47+
export const enableLogStringRefsProd: null | ((string, string) => void) = null;
4748
export const enableFilterEmptyStringAttributesDOM = true;
4849
export const enableGetInspectorDataForInstanceInProduction = false;
4950
export const enableFabricCompleteRootInCommitPhase = false;

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const enableUseEffectEventHook = false;
4646
export const favorSafetyOverHydrationPerf = true;
4747
export const enableComponentStackLocations = true;
4848
export const enableLegacyFBSupport = false;
49+
export const enableLogStringRefsProd: null | ((string, string) => void) = null;
4950
export const enableFilterEmptyStringAttributesDOM = true;
5051
export const enableGetInspectorDataForInstanceInProduction = false;
5152
export const enableRenderableContext = false;

packages/shared/forks/ReactFeatureFlags.www-dynamic.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
2121
export const enableDeferRootSchedulingToMicrotask = __VARIANT__;
2222
export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__;
2323
export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__;
24+
export const enableLogStringRefsProd: null | ((string, string) => void) = null;
2425
export const enableNoCloningMemoCache = __VARIANT__;
2526
export const enableObjectFiber = __VARIANT__;
2627
export const enableRenderableContext = __VARIANT__;

packages/shared/forks/ReactFeatureFlags.www.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,21 @@ export const {
2222
enableDebugTracing,
2323
enableDeferRootSchedulingToMicrotask,
2424
enableDO_NOT_USE_disableStrictPassiveEffect,
25+
enableHiddenSubtreeInsertionEffectCleanup,
2526
enableInfiniteRenderLoopDetection,
27+
enableLogStringRefsProd,
2628
enableNoCloningMemoCache,
2729
enableObjectFiber,
2830
enableRenderableContext,
2931
enableRetryLaneExpiration,
32+
enableSiblingPrerendering,
3033
enableTransitionTracing,
3134
enableTrustedTypesIntegration,
32-
enableHiddenSubtreeInsertionEffectCleanup,
3335
favorSafetyOverHydrationPerf,
3436
renameElementSymbol,
3537
retryLaneExpirationMs,
3638
syncLaneExpirationMs,
3739
transitionLaneExpirationMs,
38-
enableSiblingPrerendering,
3940
} = dynamicFeatureFlags;
4041

4142
// On WWW, __EXPERIMENTAL__ is used for a new modern build.

scripts/flags/flags.js

+23-7
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ function getNextMajorFlagValue(flag) {
172172
const value = ReactFeatureFlagsMajor[flag];
173173
if (value === true || value === 'next') {
174174
return '✅';
175-
} else if (value === false || value === 'experimental') {
175+
} else if (value === false || value === null || value === 'experimental') {
176176
return '❌';
177177
} else if (value === 'profile') {
178178
return '📊';
@@ -189,7 +189,12 @@ function getOSSCanaryFlagValue(flag) {
189189
const value = ReactFeatureFlags[flag];
190190
if (value === true) {
191191
return '✅';
192-
} else if (value === false || value === 'experimental' || value === 'next') {
192+
} else if (
193+
value === false ||
194+
value === null ||
195+
value === 'experimental' ||
196+
value === 'next'
197+
) {
193198
return '❌';
194199
} else if (value === 'profile') {
195200
return '📊';
@@ -206,7 +211,7 @@ function getOSSExperimentalFlagValue(flag) {
206211
const value = ReactFeatureFlags[flag];
207212
if (value === true || value === 'experimental') {
208213
return '✅';
209-
} else if (value === false || value === 'next') {
214+
} else if (value === false || value === null || value === 'next') {
210215
return '❌';
211216
} else if (value === 'profile') {
212217
return '📊';
@@ -225,7 +230,7 @@ function getWWWModernFlagValue(flag) {
225230
const value = ReactFeatureFlagsWWW[flag];
226231
if (value === true || value === 'experimental') {
227232
return '✅';
228-
} else if (value === false || value === 'next') {
233+
} else if (value === false || value === null || value === 'next') {
229234
return '❌';
230235
} else if (value === 'profile') {
231236
return '📊';
@@ -244,7 +249,12 @@ function getWWWClassicFlagValue(flag) {
244249
const value = ReactFeatureFlagsWWW[flag];
245250
if (value === true) {
246251
return '✅';
247-
} else if (value === false || value === 'experimental' || value === 'next') {
252+
} else if (
253+
value === false ||
254+
value === null ||
255+
value === 'experimental' ||
256+
value === 'next'
257+
) {
248258
return '❌';
249259
} else if (value === 'profile') {
250260
return '📊';
@@ -265,7 +275,7 @@ function getRNNextMajorFlagValue(flag) {
265275
return '✅';
266276
} else if (value === 'next-todo') {
267277
return '📋';
268-
} else if (value === false || value === 'experimental') {
278+
} else if (value === false || value === null || value === 'experimental') {
269279
return '❌';
270280
} else if (value === 'profile') {
271281
return '📊';
@@ -286,6 +296,7 @@ function getRNOSSFlagValue(flag) {
286296
return '✅';
287297
} else if (
288298
value === false ||
299+
value === null ||
289300
value === 'experimental' ||
290301
value === 'next' ||
291302
value === 'next-todo'
@@ -308,7 +319,12 @@ function getRNFBFlagValue(flag) {
308319
const value = ReactFeatureFlagsNativeFB[flag];
309320
if (value === true) {
310321
return '✅';
311-
} else if (value === false || value === 'experimental' || value === 'next') {
322+
} else if (
323+
value === false ||
324+
value === null ||
325+
value === 'experimental' ||
326+
value === 'next'
327+
) {
312328
return '❌';
313329
} else if (value === 'profile') {
314330
return '📊';

0 commit comments

Comments
 (0)