diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 387dafb6e5a1f..19c320b05dfcf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -29,6 +29,8 @@ import { isArrayType, isMutableEffect, isObjectType, + isRefValueType, + isUseRefType, } from "../HIR/HIR"; import { FunctionSignature } from "../HIR/ObjectShape"; import { @@ -521,7 +523,12 @@ class InferenceState { break; } case Effect.Mutate: { - if (valueKind.kind === ValueKind.Context) { + if ( + isRefValueType(place.identifier) || + isUseRefType(place.identifier) + ) { + // no-op: refs are validate via ValidateNoRefAccessInRender + } else if (valueKind.kind === ValueKind.Context) { functionEffect = { kind: "ContextMutation", loc: place.loc, @@ -560,7 +567,12 @@ class InferenceState { break; } case Effect.Store: { - if (valueKind.kind === ValueKind.Context) { + if ( + isRefValueType(place.identifier) || + isUseRefType(place.identifier) + ) { + // no-op: refs are validate via ValidateNoRefAccessInRender + } else if (valueKind.kind === ValueKind.Context) { functionEffect = { kind: "ContextMutation", loc: place.loc, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.expect.md new file mode 100644 index 0000000000000..539c9e71ec828 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.expect.md @@ -0,0 +1,109 @@ + +## Input + +```javascript +// @validateRefAccessDuringRender +import { useRef } from "react"; + +function Component() { + const ref = useRef(null); + + const setRef = () => { + if (ref.current !== null) { + ref.current = ""; + } + }; + + const onClick = () => { + setRef(); + }; + + return ( + <> + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.tsx new file mode 100644 index 0000000000000..14a5fd9aa5bc4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.tsx @@ -0,0 +1,28 @@ +// @validateRefAccessDuringRender +import { useRef } from "react"; + +function Component() { + const ref = useRef(null); + + const setRef = () => { + if (ref.current !== null) { + ref.current = ""; + } + }; + + const onClick = () => { + setRef(); + }; + + return ( + <> + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx.tsx new file mode 100644 index 0000000000000..74410e119a285 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx.tsx @@ -0,0 +1,24 @@ +// @validateRefAccessDuringRender +import { useRef } from "react"; + +function Component() { + const ref = useRef(null); + + const onClick = () => { + if (ref.current !== null) { + ref.current = ""; + } + }; + + return ( + <> + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx-indirect.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx-indirect.tsx new file mode 100644 index 0000000000000..87cc6d42446be --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx-indirect.tsx @@ -0,0 +1,28 @@ +// @validateRefAccessDuringRender +import { useRef } from "react"; + +function Component() { + const ref = useRef(null); + + const setRef = () => { + if (ref.current !== null) { + ref.current.value = ""; + } + }; + + const onClick = () => { + setRef(); + }; + + return ( + <> + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx.tsx new file mode 100644 index 0000000000000..b9b7a2dd8e67b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx.tsx @@ -0,0 +1,24 @@ +// @validateRefAccessDuringRender +import { useRef } from "react"; + +function Component() { + const ref = useRef(null); + + const onClick = () => { + if (ref.current !== null) { + ref.current.value = ""; + } + }; + + return ( + <> + +