diff --git a/packages/data/src/components/use-select/test/index.js b/packages/data/src/components/use-select/test/index.js
index 7e507e4a4b2b78..4f7ab0e2589316 100644
--- a/packages/data/src/components/use-select/test/index.js
+++ b/packages/data/src/components/use-select/test/index.js
@@ -118,8 +118,7 @@ describe( 'useSelect', () => {
expect( screen.getByRole( 'status' ) ).toHaveTextContent( 'bar' );
} );
- // TODO: this might be impossible to pull off in React 18 without `useSyncExternalStore`
- it( 'avoid calling nested listener after unmounted', async () => {
+ it( 'does not rerender a nested component that is to be unmounted', () => {
registry.registerStore( 'toggler', {
reducer: ( state = false, action ) =>
action.type === 'TOGGLE' ? ! state : state,
@@ -134,16 +133,16 @@ describe( 'useSelect', () => {
const mapSelect = ( select ) => select( 'toggler' ).get();
const mapSelectChild = jest.fn( mapSelect );
- function Child() {
+ const Child = jest.fn( () => {
const show = useSelect( mapSelectChild, [] );
return show ? 'yes' : 'no';
- }
+ } );
const mapSelectParent = jest.fn( mapSelect );
- function Parent() {
+ const Parent = jest.fn( () => {
const show = useSelect( mapSelectParent, [] );
return show ? : 'none';
- }
+ } );
render(
@@ -155,14 +154,10 @@ describe( 'useSelect', () => {
expect( screen.getByText( 'none' ) ).toBeInTheDocument();
expect( mapSelectParent ).toHaveBeenCalledTimes( 2 );
expect( mapSelectChild ).toHaveBeenCalledTimes( 0 );
+ expect( Parent ).toHaveBeenCalledTimes( 1 );
+ expect( Child ).toHaveBeenCalledTimes( 0 );
- // act() does batched updates internally, i.e., any scheduled setStates or effects
- // will be executed only after the dispatch finishes. But we want to opt out of
- // batched updates here. We want all the setStates to be done synchronously, as the
- // store listeners are called. The async/await code is a trick to do it: do the
- // dispatch in a different event loop tick, where the batched updates are no longer active.
- await act( async () => {
- await Promise.resolve();
+ act( () => {
registry.dispatch( 'toggler' ).toggle();
} );
@@ -170,18 +165,21 @@ describe( 'useSelect', () => {
expect( screen.getByText( 'yes' ) ).toBeInTheDocument();
expect( mapSelectParent ).toHaveBeenCalledTimes( 3 );
expect( mapSelectChild ).toHaveBeenCalledTimes( 2 );
+ expect( Parent ).toHaveBeenCalledTimes( 2 );
+ expect( Child ).toHaveBeenCalledTimes( 1 );
- await act( async () => {
- await Promise.resolve();
+ act( () => {
registry.dispatch( 'toggler' ).toggle();
} );
// Check that child was unmounted without any extra state update being performed on it.
- // I.e., `mapSelectChild` was never called again, and no "state update on an unmounted
- // component" warning was triggered.
+ // I.e., `mapSelectChild` was called again, and state update was scheduled, we cannot
+ // avoid that, but the state update is never executed and doesn't do a rerender.
expect( screen.getByText( 'none' ) ).toBeInTheDocument();
expect( mapSelectParent ).toHaveBeenCalledTimes( 4 );
- expect( mapSelectChild ).toHaveBeenCalledTimes( 2 );
+ expect( mapSelectChild ).toHaveBeenCalledTimes( 3 );
+ expect( Parent ).toHaveBeenCalledTimes( 3 );
+ expect( Child ).toHaveBeenCalledTimes( 1 );
} );
describe( 'rerenders as expected with various mapSelect return types', () => {