From 0ba4d7b0d80d942dc8f074f7ce0536e6b2559fbf Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 4 Apr 2023 11:05:33 -0400 Subject: [PATCH] DevTools: Inline references to fiber flags (#26542) We shouldn't be referencing internal fields like fiber's `flag` directly of DevTools. It's an implementation detail. However, over the years a few of these have snuck in. Because of how DevTools is currently shipped, where it's expected to be backwards compatible with older versions of React, this prevents us from refactoring those fields inside the reconciler. The plan we have to address this is to fix how DevTools is shipped: DevTools will be released in lockstep with each version of React. Until then, though, I need a temporary solution because it's blocking a feature I'm working on. So in meantime, I'm going to have to fork the DevTool's code based on the React version, like we already do with the fiber TypeOfWork enum. As a first step, I've inlined all the references to fiber flags into the specific call sites where they are used. Eventually we'll import these functions from the reconciler so they stay in sync, rather than maintaining duplicate copies of the logic. --- .../src/backend/ReactFiberFlags.js | 17 ---------- .../src/backend/renderer.js | 32 +++++++++++-------- 2 files changed, 19 insertions(+), 30 deletions(-) delete mode 100644 packages/react-devtools-shared/src/backend/ReactFiberFlags.js diff --git a/packages/react-devtools-shared/src/backend/ReactFiberFlags.js b/packages/react-devtools-shared/src/backend/ReactFiberFlags.js deleted file mode 100644 index 8cc47dc7ce..0000000000 --- a/packages/react-devtools-shared/src/backend/ReactFiberFlags.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -// This list of flags must be synced with the following file: -// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberFlags.js - -export const NoFlags = /* */ 0b000000000000000000000000000; -export const PerformedWork = /* */ 0b000000000000000000000000001; -export const Placement = /* */ 0b000000000000000000000000010; -export const DidCapture = /* */ 0b000000000000000000010000000; -export const Hydrating = /* */ 0b000000000000001000000000000; diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 00558a4bf7..d37497078e 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -88,13 +88,6 @@ import { MEMO_SYMBOL_STRING, SERVER_CONTEXT_SYMBOL_STRING, } from './ReactSymbols'; -import { - DidCapture, - NoFlags, - PerformedWork, - Placement, - Hydrating, -} from './ReactFiberFlags'; import {format} from './utils'; import { enableProfilerChangedHookIndices, @@ -1555,7 +1548,10 @@ export function attach( case ForwardRef: // For types that execute user code, we check PerformedWork effect. // We don't reflect bailouts (either referential or sCU) in DevTools. - // eslint-disable-next-line no-bitwise + // TODO: This flag is a leaked implementation detail. Once we start + // releasing DevTools in lockstep with React, we should import a + // function from the reconciler instead. + const PerformedWork = 0b000000000000000000000000001; return (getFiberFlags(nextFiber) & PerformedWork) === PerformedWork; // Note: ContextConsumer only gets PerformedWork effect in 16.3.3+ // so it won't get highlighted with React 16.3.0 to 16.3.2. @@ -2843,7 +2839,12 @@ export function attach( let nextNode: Fiber = node; do { node = nextNode; - if ((node.flags & (Placement | Hydrating)) !== NoFlags) { + // TODO: This function, and these flags, are a leaked implementation + // detail. Once we start releasing DevTools in lockstep with React, we + // should import a function from the reconciler instead. + const Placement = 0b000000000000000000000000010; + const Hydrating = 0b000000000000001000000000000; + if ((node.flags & (Placement | Hydrating)) !== 0) { // This is an insertion or in-progress hydration. The nearest possible // mounted fiber is the parent but we need to continue to figure out // if that one is still mounted. @@ -3300,16 +3301,21 @@ export function attach( const errors = fiberIDToErrorsMap.get(id) || new Map(); const warnings = fiberIDToWarningsMap.get(id) || new Map(); - const isErrored = - (fiber.flags & DidCapture) !== NoFlags || - forceErrorForFiberIDs.get(id) === true; - + let isErrored = false; let targetErrorBoundaryID; if (isErrorBoundary(fiber)) { // if the current inspected element is an error boundary, // either that we want to use it to toggle off error state // or that we allow to force error state on it if it's within another // error boundary + // + // TODO: This flag is a leaked implementation detail. Once we start + // releasing DevTools in lockstep with React, we should import a function + // from the reconciler instead. + const DidCapture = 0b000000000000000000010000000; + isErrored = + (fiber.flags & DidCapture) !== 0 || + forceErrorForFiberIDs.get(id) === true; targetErrorBoundaryID = isErrored ? id : getNearestErrorBoundaryID(fiber); } else { targetErrorBoundaryID = getNearestErrorBoundaryID(fiber);