Skip to content

Commit

Permalink
Adjust useMergeRef to not depend on ref order
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Mar 9, 2021
1 parent 7e7c3c3 commit b326f99
Showing 1 changed file with 27 additions and 22 deletions.
49 changes: 27 additions & 22 deletions packages/compose/src/hooks/use-merge-refs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import { useRef, useCallback, useLayoutEffect } from '@wordpress/element';
/** @typedef {import('@wordpress/element').RefObject} RefObject */
/** @typedef {import('@wordpress/element').RefCallback} RefCallback */

function assignRef( ref, value ) {
if ( typeof ref === 'function' ) {
ref( value );
} else if ( ref && ref.hasOwnProperty( 'current' ) ) {
ref.current = value;
}
}

/**
* Merges refs into one ref callback. Ensures the merged ref callbacks are only
* called when it changes (as a result of a `useCallback` dependency update) or
Expand All @@ -22,7 +30,7 @@ import { useRef, useCallback, useLayoutEffect } from '@wordpress/element';
export default function useMergeRefs( refs ) {
const element = useRef( null );
const didElementChange = useRef( false );
const previousRefs = useRef( refs );
const previousRefs = useRef();
const currentRefs = useRef( refs );

// Update on render before the ref callback is called, so the ref callback
Expand All @@ -33,23 +41,24 @@ export default function useMergeRefs( refs ) {
// ref with the node, except when the element changes in the same cycle, in
// which case the ref callbacks will already have been called.
useLayoutEffect( () => {
refs.forEach( ( ref, index ) => {
const previousRef = previousRefs.current[ index ];

if ( ref && ref.hasOwnProperty( 'current' ) ) {
ref.current = element.current;
} else if (
typeof ref === 'function' &&
ref !== previousRef &&
didElementChange.current === false
) {
if ( previousRef ) {
previousRef( null );
if ( didElementChange.current === false ) {
if ( previousRefs.current ) {
for ( const previousRef of previousRefs.current ) {
if ( ! refs.includes( previousRef ) ) {
assignRef( previousRef, null );
}
}
}

ref( element.current );
for ( const ref of refs ) {
if (
! previousRefs.current ||
! previousRefs.current.includes( ref )
) {
assignRef( ref, element.current );
}
}
} );
}

previousRefs.current = refs;
didElementChange.current = false;
Expand All @@ -68,12 +77,8 @@ export default function useMergeRefs( refs ) {
const refsToUpdate = value ? currentRefs.current : previousRefs.current;

// Update the latest refs.
refsToUpdate.forEach( ( ref ) => {
if ( typeof ref === 'function' ) {
ref( value );
} else if ( ref && ref.hasOwnProperty( 'current' ) ) {
ref.current = value;
}
} );
for ( const ref of refsToUpdate ) {
assignRef( ref, value );
}
}, [] );
}

0 comments on commit b326f99

Please sign in to comment.