mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
Fix indices of hooks in devtools when using useSyncExternalStore (#34547)
## Summary This PR updates getChangedHooksIndices to account for the fact that useSyncExternalStore internally mounts two hooks, while DevTools should treat it as a single user-facing hook. It introduces a helper isUseSyncExternalStoreHook to detect this case and adjust iteration so the extra internal hook is skipped when counting changes. Before: https://github.com/user-attachments/assets/0db72a4e-21f7-44c7-ba02-669a272631e5 After: https://github.com/user-attachments/assets/4da71392-0396-408d-86a7-6fbc82d8c4f5 ## How did you test this change? I used this component to reproduce this issue locally (I followed instructions in `packages/react-devtools/CONTRIBUTING.md`). ```ts function Test() { // 1 React.useSyncExternalStore( () => {}, () => {}, () => {}, ); // 2 const [state, setState] = useState('test'); return ( <> <div onClick={() => setState(Math.random())} style={{backgroundColor: 'red'}}> {state} </div> </> ); } ```
This commit is contained in:
parent
613cf80f26
commit
39c6545cef
|
|
@ -1913,6 +1913,20 @@ export function attach(
|
|||
return false;
|
||||
}
|
||||
|
||||
function isUseSyncExternalStoreHook(hookObject: any): boolean {
|
||||
const queue = hookObject.queue;
|
||||
if (!queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const boundHasOwnProperty = hasOwnProperty.bind(queue);
|
||||
return (
|
||||
boundHasOwnProperty('value') &&
|
||||
boundHasOwnProperty('getSnapshot') &&
|
||||
typeof queue.getSnapshot === 'function'
|
||||
);
|
||||
}
|
||||
|
||||
function isHookThatCanScheduleUpdate(hookObject: any) {
|
||||
const queue = hookObject.queue;
|
||||
if (!queue) {
|
||||
|
|
@ -1929,12 +1943,7 @@ export function attach(
|
|||
return true;
|
||||
}
|
||||
|
||||
// Detect useSyncExternalStore()
|
||||
return (
|
||||
boundHasOwnProperty('value') &&
|
||||
boundHasOwnProperty('getSnapshot') &&
|
||||
typeof queue.getSnapshot === 'function'
|
||||
);
|
||||
return isUseSyncExternalStoreHook(hookObject);
|
||||
}
|
||||
|
||||
function didStatefulHookChange(prev: any, next: any): boolean {
|
||||
|
|
@ -1955,10 +1964,18 @@ export function attach(
|
|||
|
||||
const indices = [];
|
||||
let index = 0;
|
||||
|
||||
while (next !== null) {
|
||||
if (didStatefulHookChange(prev, next)) {
|
||||
indices.push(index);
|
||||
}
|
||||
|
||||
// useSyncExternalStore creates 2 internal hooks, but we only count it as 1 user-facing hook
|
||||
if (isUseSyncExternalStoreHook(next)) {
|
||||
next = next.next;
|
||||
prev = prev.next;
|
||||
}
|
||||
|
||||
next = next.next;
|
||||
prev = prev.next;
|
||||
index++;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user