Skip to content

Commit 47d632f

Browse files
committed
Filter out deleted components that are added to the updaters list
1 parent 8116347 commit 47d632f

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

packages/react-devtools-shared/src/__tests__/profilingCache-test.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,4 +752,97 @@ describe('ProfilingCache', () => {
752752
utils.act(() => store.profilerStore.stopProfiling());
753753
expect(container.textContent).toBe('About');
754754
});
755+
756+
it('components that were deleted and added to updaters during the layout phase should not crash', () => {
757+
let setBarUnmounted;
758+
function Bar() {
759+
const [, setState] = React.useState(false);
760+
761+
React.useLayoutEffect(() => {
762+
return () => setState(true);
763+
});
764+
765+
return null;
766+
}
767+
768+
function App() {
769+
const [barUnmounted, _setBarUnmounted] = React.useState(false);
770+
setBarUnmounted = _setBarUnmounted;
771+
return <>{!barUnmounted && <Bar />}</>;
772+
}
773+
774+
const root = ReactDOM.createRoot(document.createElement('div'));
775+
utils.act(() => root.render(<App />));
776+
utils.act(() => store.profilerStore.startProfiling());
777+
utils.act(() => setBarUnmounted(true));
778+
utils.act(() => store.profilerStore.stopProfiling());
779+
780+
const updaters = store.profilerStore.getCommitData(store.roots[0], 0)
781+
.updaters;
782+
expect(updaters.length).toEqual(1);
783+
expect(updaters[0].displayName).toEqual('App');
784+
});
785+
786+
it('components in a deleted subtree and added to updaters during the layout phase should not crash', () => {
787+
function Foo() {
788+
return <Bar />;
789+
}
790+
791+
let setBarUnmounted;
792+
function Bar() {
793+
const [, setState] = React.useState(false);
794+
795+
React.useLayoutEffect(() => {
796+
return () => setState(true);
797+
});
798+
799+
return null;
800+
}
801+
802+
function App() {
803+
const [barUnmounted, _setBarUnmounted] = React.useState(false);
804+
setBarUnmounted = _setBarUnmounted;
805+
return <>{!barUnmounted && <Foo />}</>;
806+
}
807+
808+
const root = ReactDOM.createRoot(document.createElement('div'));
809+
utils.act(() => root.render(<App />));
810+
utils.act(() => store.profilerStore.startProfiling());
811+
utils.act(() => setBarUnmounted(true));
812+
utils.act(() => store.profilerStore.stopProfiling());
813+
814+
const updaters = store.profilerStore.getCommitData(store.roots[0], 0)
815+
.updaters;
816+
expect(updaters.length).toEqual(1);
817+
expect(updaters[0].displayName).toEqual('App');
818+
});
819+
820+
it('components that were deleted should not be added to updaters during the passive phase', () => {
821+
let setBarUnmounted;
822+
function Bar() {
823+
const [, setState] = React.useState(false);
824+
React.useEffect(() => {
825+
return () => setState(true);
826+
});
827+
828+
return null;
829+
}
830+
831+
function App() {
832+
const [barUnmounted, _setBarUnmounted] = React.useState(false);
833+
setBarUnmounted = _setBarUnmounted;
834+
return <>{!barUnmounted && <Bar />}</>;
835+
}
836+
837+
const root = ReactDOM.createRoot(document.createElement('div'));
838+
utils.act(() => root.render(<App />));
839+
utils.act(() => store.profilerStore.startProfiling());
840+
utils.act(() => setBarUnmounted(true));
841+
utils.act(() => store.profilerStore.stopProfiling());
842+
843+
const updaters = store.profilerStore.getCommitData(store.roots[0], 0)
844+
.updaters;
845+
expect(updaters.length).toEqual(1);
846+
expect(updaters[0].displayName).toEqual('App');
847+
});
755848
});

packages/react-devtools-shared/src/backend/renderer.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2573,7 +2573,9 @@ export function attach(
25732573

25742574
function getUpdatersList(root): Array<SerializedElement> | null {
25752575
return root.memoizedUpdaters != null
2576-
? Array.from(root.memoizedUpdaters).map(fiberToSerializedElement)
2576+
? Array.from(root.memoizedUpdaters)
2577+
.filter(fiber => getFiberIDUnsafe(fiber) !== null)
2578+
.map(fiberToSerializedElement)
25772579
: null;
25782580
}
25792581

0 commit comments

Comments
 (0)