From 179197a22a0c00bc30c1a44275e7b4b1b2cec019 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Wed, 14 Aug 2024 13:54:38 -0400 Subject: [PATCH] [compiler] Allow different dependencies from explicit memoization when dependency is a ref Summary: In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source. ghstack-source-id: 685d859d1eed5d1e19dbbbfadc75be3875ddb6ea Pull Request resolved: https://github.com/facebook/react/pull/30679 --- .../src/HIR/HIR.ts | 7 ++- ...-callback-passed-to-jsx-indirect.expect.md | 53 +++++------------- ...ng-ref-in-callback-passed-to-jsx.expect.md | 34 +++-------- ...-callback-passed-to-jsx-indirect.expect.md | 53 +++++------------- ...operty-in-callback-passed-to-jsx.expect.md | 34 +++-------- .../allow-passing-refs-as-props.expect.md | 9 ++- ...ow-ref-access-in-effect-indirect.expect.md | 37 ++++++------ .../allow-ref-access-in-effect.expect.md | 9 ++- ...access-in-unused-callback-nested.expect.md | 9 ++- .../capture-ref-for-later-mutation.expect.md | 45 +++++++-------- ...ve-use-memo-ref-missing-reactive.expect.md | 48 ++++++++++++++++ ....preserve-use-memo-ref-missing-reactive.ts | 19 +++++++ ...preserve-use-memo-ref-missing-ok.expect.md | 56 +++++++++++++++++++ .../preserve-use-memo-ref-missing-ok.ts | 17 ++++++ .../compiler/react-namespace.expect.md | 11 ++-- ...-current-aliased-no-added-to-dep.expect.md | 17 ++---- ...f-current-field-not-added-to-dep.expect.md | 17 ++---- ...ent-field-write-not-added-to-dep.expect.md | 17 ++---- .../ref-current-not-added-to-dep.expect.md | 17 ++---- ...t-optional-field-no-added-to-dep.expect.md | 17 ++---- ...f-current-write-not-added-to-dep.expect.md | 17 ++---- .../fixtures/compiler/ref-in-effect.expect.md | 9 ++- .../ref-like-name-in-useCallback-2.expect.md | 9 ++- .../ref-like-name-in-useCallback.expect.md | 9 ++- ...ng-same-ref-preserve-memoization.expect.md | 10 ++-- ...ed-property-preserve-memoization.expect.md | 9 ++- ...Callback-set-ref-nested-property.expect.md | 9 ++- ...-value-dont-preserve-memoization.expect.md | 9 ++- ...t-ref-value-preserve-memoization.expect.md | 9 ++- 29 files changed, 306 insertions(+), 310 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-ref-missing-ok.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-ref-missing-ok.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 1e807d6d2a5d0..84671712e9305 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -1616,7 +1616,12 @@ export function isDispatcherType(id: Identifier): boolean { } export function isStableType(id: Identifier): boolean { - return isSetStateType(id) || isSetActionStateType(id) || isDispatcherType(id); + return ( + isSetStateType(id) || + isSetActionStateType(id) || + isDispatcherType(id) || + isUseRefType(id) + ); } export function isUseEffectHookType(id: Identifier): boolean { 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 index 7e6dcaff76d10..70320c376274a 100644 --- 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 @@ -40,62 +40,37 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen import { useRef } from "react"; function Component() { - const $ = _c(10); + const $ = _c(2); const ref = useRef(null); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { + const setRef = () => { if (ref.current !== null) { ref.current = ""; } }; + + t0 = () => { + setRef(); + }; $[0] = t0; } else { t0 = $[0]; } - const setRef = t0; + const onClick = t0; let t1; - if ($[1] !== setRef) { - t1 = () => { - setRef(); - }; - $[1] = setRef; - $[2] = t1; - } else { - t1 = $[2]; - } - const onClick = t1; - let t2; - if ($[3] !== ref) { - t2 = ; - $[3] = ref; - $[4] = t2; - } else { - t2 = $[4]; - } - let t3; - if ($[5] !== onClick) { - t3 =