From b000019578a417ec0a1aeec8bda689db240cb28e Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 22 Jan 2025 14:15:48 +0000 Subject: [PATCH] DevTools: support useEffectEvent and forward-fix experimental prefix support (#32106) - Adds support for `experimental_useEffectEvent`, now DevTools will be able to display this hook for inspected element - Added a use case to DevTools shell, couldn't add case, because we are using ReactTestRenderer, which has the corresponding flag disabled. - Forward-fix logic for handling `experimental` prefix that was added in https://github.com/facebook/react/pull/32088. ![Screenshot 2025-01-16 at 21 24 12](https://github.com/user-attachments/assets/6fb8ff2a-be47-47b5-bbfc-73d3a586657c) --- .../react-debug-tools/src/ReactDebugHooks.js | 24 +++++++++++++- .../InspectableElements.js | 2 ++ .../app/InspectableElements/UseEffectEvent.js | 32 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/react-devtools-shell/src/app/InspectableElements/UseEffectEvent.js diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 2e1fcb19a6..f30489b7f6 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -127,6 +127,13 @@ function getPrimitiveStackCache(): Map> { } Dispatcher.useId(); + + if (typeof Dispatcher.useResourceEffect === 'function') { + Dispatcher.useResourceEffect(() => ({}), []); + } + if (typeof Dispatcher.useEffectEvent === 'function') { + Dispatcher.useEffectEvent((args: empty) => {}); + } } finally { readHookLog = hookLog; hookLog = []; @@ -749,6 +756,20 @@ function useResourceEffect( }); } +function useEffectEvent) => mixed>(callback: F): F { + nextHook(); + hookLog.push({ + displayName: null, + primitive: 'EffectEvent', + stackError: new Error(), + value: callback, + debugInfo: null, + dispatcherHookName: 'EffectEvent', + }); + + return callback; +} + const Dispatcher: DispatcherType = { use, readContext, @@ -773,6 +794,7 @@ const Dispatcher: DispatcherType = { useFormState, useActionState, useHostTransitionStatus, + useEffectEvent, useResourceEffect, }; @@ -962,7 +984,7 @@ function parseHookName(functionName: void | string): string { startIndex += 'unstable_'.length; } - if (functionName.slice(startIndex).startsWith('unstable_')) { + if (functionName.slice(startIndex).startsWith('experimental_')) { startIndex += 'experimental_'.length; } diff --git a/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js b/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js index abc6eee336..95f104925b 100644 --- a/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js +++ b/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js @@ -19,6 +19,7 @@ import NestedProps from './NestedProps'; import SimpleValues from './SimpleValues'; import SymbolKeys from './SymbolKeys'; import UseMemoCache from './UseMemoCache'; +import UseEffectEvent from './UseEffectEvent'; // TODO Add Immutable JS example @@ -36,6 +37,7 @@ export default function InspectableElements(): React.Node { + ); } diff --git a/packages/react-devtools-shell/src/app/InspectableElements/UseEffectEvent.js b/packages/react-devtools-shell/src/app/InspectableElements/UseEffectEvent.js new file mode 100644 index 0000000000..e55f6a3c55 --- /dev/null +++ b/packages/react-devtools-shell/src/app/InspectableElements/UseEffectEvent.js @@ -0,0 +1,32 @@ +import * as React from 'react'; + +const {experimental_useEffectEvent, useState, useEffect} = React; + +export default function UseEffectEvent(): React.Node { + return ( + <> + + + + ); +} + +function SingleHookCase() { + const onClick = experimental_useEffectEvent(() => {}); + + return
; +} + +function useCustomHook() { + const [state, setState] = useState(); + const onClick = experimental_useEffectEvent(() => {}); + useEffect(() => {}); + + return [state, setState, onClick]; +} + +function HookTreeCase() { + const onClick = useCustomHook(); + + return
; +}