Skip to content

Commit

Permalink
useSelect: improve transition from async to sync mode (#40680)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnajdr committed Apr 28, 2022
1 parent be92ce8 commit 8832db9
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 17 deletions.
22 changes: 8 additions & 14 deletions packages/data/src/components/use-select/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,6 @@ export default function useSelect( mapSelect, deps ) {

const registry = useRegistry();
const isAsync = useAsyncMode();
// React can sometimes clear the `useMemo` cache.
// We use the cache-stable `useMemoOne` to avoid
// losing queues.
const queueContext = useMemoOne( () => ( { queue: true } ), [ registry ] );
const [ , forceRender ] = useReducer( ( s ) => s + 1, 0 );

const latestRegistry = useRef( registry );
const latestMapSelect = useRef();
Expand Down Expand Up @@ -147,11 +142,13 @@ export default function useSelect( mapSelect, deps ) {
mapOutput = latestMapOutput.current;
const hasReplacedRegistry = latestRegistry.current !== registry;
const hasReplacedMapSelect = latestMapSelect.current !== _mapSelect;
const hasLeftAsyncMode = latestIsAsync.current && ! isAsync;
const lastMapSelectFailed = !! latestMapOutputError.current;

if (
hasReplacedRegistry ||
hasReplacedMapSelect ||
hasLeftAsyncMode ||
lastMapSelectFailed
) {
try {
Expand All @@ -178,19 +175,16 @@ export default function useSelect( mapSelect, deps ) {

latestRegistry.current = registry;
latestMapSelect.current = _mapSelect;
latestIsAsync.current = isAsync;
latestMapOutput.current = mapOutput;
latestMapOutputError.current = undefined;

// This has to run after the other ref updates
// to avoid using stale values in the flushed
// callbacks or potentially overwriting a
// changed `latestMapOutput.current`.
if ( latestIsAsync.current !== isAsync ) {
latestIsAsync.current = isAsync;
renderQueue.flush( queueContext );
}
} );

// React can sometimes clear the `useMemo` cache.
// We use the cache-stable `useMemoOne` to avoid
// losing queues.
const queueContext = useMemoOne( () => ( { queue: true } ), [ registry ] );
const [ , forceRender ] = useReducer( ( s ) => s + 1, 0 );
const isMounted = useRef( false );

useIsomorphicLayoutEffect( () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/data/src/components/use-select/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -884,10 +884,10 @@ describe( 'useSelect', () => {
// Ensure the async update was flushed during the rerender.
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 1 );

// initial render + subscription check + flushed store update
// initial render + subscription check + rerender with isAsync=false
expect( selectSpy ).toHaveBeenCalledTimes( 3 );
// initial render + rerender with isAsync=false + store state update
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
// initial render + rerender with isAsync=false
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
} );

it( 'cancels scheduled updates when mapSelect function changes', async () => {
Expand Down

0 comments on commit 8832db9

Please sign in to comment.