diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts index abbb7d8476981..6656e7857822c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts @@ -402,14 +402,26 @@ function validateNoRefAccessInRenderImpl( } const objType = env.get(instr.value.object.identifier.id); let lookupType: null | RefAccessType = null; - if (objType?.kind === 'Structure') { - lookupType = objType.value; - } else if (objType?.kind === 'Ref') { - lookupType = { - kind: 'RefValue', - loc: instr.loc, - refId: objType.refId, - }; + if (objType?.kind === 'Ref') { + // Only loading .current from a ref should be treated as a ref value access + if ( + instr.value.kind === 'PropertyLoad' && + instr.value.property === 'current' + ) { + lookupType = { + kind: 'RefValue', + loc: instr.loc, + refId: objType.refId, + }; + } + } else if (objType?.kind === 'Structure') { + // For structures (like props objects or objects containing refs), + // we should not automatically propagate the ref type to all properties. + // Only propagate if we're destructuring the entire object or if the + // specific property is known to be a ref. + // This prevents false positives where props.className is flagged as a ref + // just because props also contains props.ref. + lookupType = null; } env.set( instr.lvalue.identifier.id, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/false-positive-props-ref-access.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/false-positive-props-ref-access.js new file mode 100644 index 0000000000000..6a1e67895702a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/false-positive-props-ref-access.js @@ -0,0 +1,32 @@ +// @compilationMode(infer) +// Regression test for https://github.com/facebook/react/issues/34775 +// The compiler should NOT flag props.className as a ref access just because +// props also contains props.ref. Each property should be independently typed. + +import {useCallback} from 'react'; + +function Child(props: {className: string, myRef: () => void}) { + const internalRef = useCallback(() => { + console.log('ref'); + }, []); + + return ( +
+
+
+
+ ); +} + +export function Parent() { + const ref = useCallback(() => { + console.log('ref'); + }, []); + + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Parent, + params: [], +};