@wordpress/compose 8.1.0 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +5 -5
  3. package/build/higher-order/pure/index.cjs +15 -0
  4. package/build/higher-order/pure/index.cjs.map +3 -3
  5. package/build/hooks/use-media-query/index.cjs +2 -2
  6. package/build/hooks/use-media-query/index.cjs.map +2 -2
  7. package/build/hooks/use-merge-refs/index.cjs +28 -8
  8. package/build/hooks/use-merge-refs/index.cjs.map +2 -2
  9. package/build/hooks/use-viewport-match/index.cjs +1 -1
  10. package/build/hooks/use-viewport-match/index.cjs.map +2 -2
  11. package/build-module/higher-order/pure/index.mjs +5 -0
  12. package/build-module/higher-order/pure/index.mjs.map +2 -2
  13. package/build-module/hooks/use-media-query/index.mjs +2 -2
  14. package/build-module/hooks/use-media-query/index.mjs.map +2 -2
  15. package/build-module/hooks/use-merge-refs/index.mjs +28 -8
  16. package/build-module/hooks/use-merge-refs/index.mjs.map +2 -2
  17. package/build-module/hooks/use-viewport-match/index.mjs +1 -1
  18. package/build-module/hooks/use-viewport-match/index.mjs.map +2 -2
  19. package/build-types/higher-order/pure/index.d.ts.map +1 -1
  20. package/build-types/hooks/use-media-query/index.d.ts +1 -1
  21. package/build-types/hooks/use-media-query/index.d.ts.map +1 -1
  22. package/build-types/hooks/use-merge-refs/index.d.ts +7 -5
  23. package/build-types/hooks/use-merge-refs/index.d.ts.map +1 -1
  24. package/build-types/hooks/use-viewport-match/index.d.ts +1 -1
  25. package/build-types/hooks/use-viewport-match/index.d.ts.map +1 -1
  26. package/package.json +16 -12
  27. package/src/higher-order/pure/index.tsx +6 -0
  28. package/src/higher-order/pure/test/index.js +14 -81
  29. package/src/hooks/use-drop-zone/README.md +1 -1
  30. package/src/hooks/use-media-query/index.ts +10 -3
  31. package/src/hooks/use-media-query/test/ssr.js +47 -0
  32. package/src/hooks/use-merge-refs/index.ts +49 -18
  33. package/src/hooks/use-merge-refs/test/index.js +288 -0
  34. package/src/hooks/use-viewport-match/index.js +8 -2
  35. package/src/higher-order/with-network-connectivity/README.md +0 -20
  36. package/src/higher-order/with-network-connectivity/index.native.js +0 -19
  37. package/src/higher-order/with-preferred-color-scheme/index.native.js +0 -40
  38. package/src/hooks/use-constrained-tabbing/index.native.js +0 -14
  39. package/src/hooks/use-focus-outside/index.native.js +0 -170
  40. package/src/hooks/use-keyboard-shortcut/index.native.js +0 -2
  41. package/src/hooks/use-network-connectivity/index.native.js +0 -59
  42. package/src/hooks/use-network-connectivity/test/index.native.js +0 -87
  43. package/src/hooks/use-preferred-color-scheme/index.android.js +0 -30
  44. package/src/hooks/use-preferred-color-scheme/index.ios.js +0 -13
  45. package/src/hooks/use-preferred-color-scheme-style/index.native.js +0 -33
  46. package/src/hooks/use-resize-observer/index.native.js +0 -1
  47. package/src/hooks/use-resize-observer/legacy/index.native.js +0 -59
  48. package/src/hooks/use-resize-observer/legacy/test/index.native.js +0 -46
  49. package/src/index.native.js +0 -44
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-merge-refs/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAoB,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAUhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAE,CAAC,EACtC,IAAI,EAAE,GAAG,CAAE,CAAC,CAAE,EAAE,GACd,WAAW,CAAE,CAAC,CAAE,CA0DlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-merge-refs/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAoB,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AA+BhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAE,CAAC,EACtC,IAAI,EAAE,GAAG,CAAE,CAAC,CAAE,EAAE,GACd,WAAW,CAAE,CAAC,CAAE,CAkElB"}
@@ -1,6 +1,6 @@
1
1
  export type WPBreakpoint = "xhuge" | "huge" | "wide" | "xlarge" | "large" | "medium" | "small" | "mobile";
2
2
  export type WPViewportOperator = ">=" | "<";
3
- declare function useViewportMatch(breakpoint: WPBreakpoint, operator?: WPViewportOperator, view?: Window): boolean;
3
+ declare function useViewportMatch(breakpoint: WPBreakpoint, operator?: WPViewportOperator, view?: Window | undefined): boolean;
4
4
  declare namespace useViewportMatch {
5
5
  var __experimentalWidthProvider: import("react").Provider<number | null>;
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-viewport-match/index.js"],"names":[],"mappings":"AAWG,YAA0F,YAAY,GAA5F,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAc;AAsBtG,YAAsB,kBAAkB,GAA9B,IAAI,GAAG,GAAG,CAAoB;kCA4ChB,UAAU,EAb1B,YAa0B,EAAE,QAAQ,GAZpC,kBAY2C,EAAE,IAAI,GAXjD,MAW0D,GAFzD,OAAO;;;;eAoBJ,gBAAgB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-viewport-match/index.js"],"names":[],"mappings":"AAWG,YAA0F,YAAY,GAA5F,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAc;AAsBtG,YAAsB,kBAAkB,GAA9B,IAAI,GAAG,GAAG,CAAoB;kCA6C1C,UAAU,EAdA,YAcA,EACV,QAAQ,GAdE,kBAcK,EAGf,IAAI,GAhBM,MAAM,GAAC,SAgBwC,GAP9C,OAAO;;;;eA0BJ,gBAAgB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/compose",
3
- "version": "8.1.0",
3
+ "version": "8.1.1",
4
4
  "description": "WordPress higher-order components (HOCs).",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -41,26 +41,30 @@
41
41
  },
42
42
  "./package.json": "./package.json"
43
43
  },
44
- "react-native": "src/index",
45
44
  "wpScript": true,
46
45
  "types": "build-types",
47
46
  "sideEffects": false,
48
47
  "dependencies": {
49
48
  "@types/mousetrap": "^1.6.8",
50
- "@wordpress/deprecated": "^4.48.0",
51
- "@wordpress/dom": "^4.48.0",
52
- "@wordpress/element": "^8.0.0",
53
- "@wordpress/is-shallow-equal": "^5.48.0",
54
- "@wordpress/keycodes": "^4.48.0",
55
- "@wordpress/priority-queue": "^3.48.0",
56
- "@wordpress/private-apis": "^1.48.0",
57
- "@wordpress/undo-manager": "^1.48.0",
49
+ "@types/react": "^18.3.27",
50
+ "@wordpress/deprecated": "^4.48.1",
51
+ "@wordpress/dom": "^4.48.1",
52
+ "@wordpress/element": "^8.0.1",
53
+ "@wordpress/is-shallow-equal": "^5.48.1",
54
+ "@wordpress/keycodes": "^4.48.1",
55
+ "@wordpress/priority-queue": "^3.48.1",
56
+ "@wordpress/private-apis": "^1.48.1",
57
+ "@wordpress/undo-manager": "^1.48.1",
58
58
  "change-case": "^4.1.2",
59
59
  "mousetrap": "^1.6.5",
60
60
  "use-memo-one": "^1.1.1"
61
61
  },
62
62
  "devDependencies": {
63
- "mock-match-media": "0.4.2"
63
+ "@testing-library/dom": "^10.4.1",
64
+ "@testing-library/react": "^16.3.2",
65
+ "@testing-library/user-event": "^14.6.1",
66
+ "mock-match-media": "^0.4.2",
67
+ "react-dom": "^18.3.1"
64
68
  },
65
69
  "peerDependencies": {
66
70
  "react": "^18.0.0"
@@ -68,5 +72,5 @@
68
72
  "publishConfig": {
69
73
  "access": "public"
70
74
  },
71
- "gitHead": "e7856693aeb4e2522d13608cd32c994e4a97cb9c"
75
+ "gitHead": "99df7432c5c7cb83ba41146fd1f57f3c19004305"
72
76
  }
@@ -8,6 +8,7 @@ import type { ComponentType, ComponentClass } from 'react';
8
8
  */
9
9
  import { isShallowEqual } from '@wordpress/is-shallow-equal';
10
10
  import { Component } from '@wordpress/element';
11
+ import deprecated from '@wordpress/deprecated';
11
12
 
12
13
  /**
13
14
  * Internal dependencies
@@ -23,6 +24,11 @@ import { createHigherOrderComponent } from '../../utils/create-higher-order-comp
23
24
  const pure = createHigherOrderComponent( function < Props extends {} >(
24
25
  WrappedComponent: ComponentType< Props >
25
26
  ): ComponentType< Props > {
27
+ deprecated( 'wp.compose.pure', {
28
+ since: '7.1',
29
+ alternative: 'Use `memo` or `PureComponent` instead',
30
+ } );
31
+
26
32
  if ( WrappedComponent.prototype instanceof Component ) {
27
33
  return class extends ( WrappedComponent as ComponentClass< Props > ) {
28
34
  shouldComponentUpdate( nextProps: Props, nextState: any ) {
@@ -2,12 +2,11 @@
2
2
  * External dependencies
3
3
  */
4
4
  import { render, screen } from '@testing-library/react';
5
- import userEvent from '@testing-library/user-event';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
9
8
  */
10
- import { Component } from '@wordpress/element';
9
+ import { logged } from '@wordpress/deprecated';
11
10
 
12
11
  /**
13
12
  * Internal dependencies
@@ -15,88 +14,22 @@ import { Component } from '@wordpress/element';
15
14
  import pure from '../';
16
15
 
17
16
  describe( 'pure', () => {
18
- it( 'functional component should rerender only when props change', () => {
19
- let i = 0;
20
- const MyComp = pure( () => {
21
- return <p data-testid="counter">{ ++i }</p>;
22
- } );
23
- const { rerender } = render( <MyComp /> );
24
-
25
- // Updating with same props doesn't rerender.
26
- rerender( <MyComp /> );
27
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '1' );
28
-
29
- // New prop should trigger a rerender.
30
- rerender( <MyComp { ...{ prop: 'a' } } /> );
31
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '2' );
32
-
33
- // Keeping the same prop value should not rerender.
34
- rerender( <MyComp { ...{ prop: 'a' } } /> );
35
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '2' );
36
-
37
- // Changing the prop value should rerender.
38
- rerender( <MyComp { ...{ prop: 'b' } } /> );
39
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '3' );
17
+ afterEach( () => {
18
+ for ( const key in logged ) {
19
+ delete logged[ key ];
20
+ }
40
21
  } );
41
22
 
42
- it( 'class component should rerender if the props or state change', async () => {
43
- const user = userEvent.setup();
44
- let i = 0;
45
- const MyComp = pure(
46
- class extends Component {
47
- constructor() {
48
- super( ...arguments );
49
- this.state = {
50
- val: '',
51
- };
52
- }
53
- render() {
54
- return (
55
- <>
56
- <p data-testid="counter">{ ++i }</p>
57
- <input
58
- type="text"
59
- value={ this.state.val }
60
- onChange={ ( e ) =>
61
- this.setState( { val: e.target.value } )
62
- }
63
- />
64
- <input
65
- type="button"
66
- onClick={ () =>
67
- this.setState( { val: this.state.val } )
68
- }
69
- />
70
- </>
71
- );
72
- }
73
- }
74
- );
75
-
76
- const { rerender } = render( <MyComp /> );
23
+ it( 'wraps a component and logs a deprecation warning', () => {
24
+ const MyComp = pure( () => <p data-testid="content">content</p> );
77
25
 
78
- // Updating with same props doesn't rerender.
79
- rerender( <MyComp /> );
80
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '1' );
26
+ render( <MyComp /> );
81
27
 
82
- // New prop should trigger a rerender.
83
- rerender( <MyComp { ...{ prop: 'a' } } /> );
84
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '2' );
85
-
86
- // Keeping the same prop value should not rerender.
87
- rerender( <MyComp { ...{ prop: 'a' } } /> );
88
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '2' );
89
-
90
- // Changing the prop value should rerender.
91
- rerender( <MyComp { ...{ prop: 'b' } } /> );
92
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '3' );
93
-
94
- // New state value should trigger a rerender.
95
- await user.type( screen.getByRole( 'textbox' ), 'a' );
96
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '4' );
97
-
98
- // Keeping the same state value should not trigger a rerender.
99
- await user.click( screen.getByRole( 'button' ) );
100
- expect( screen.getByTestId( 'counter' ) ).toHaveTextContent( '4' );
28
+ expect( console ).toHaveWarnedWith(
29
+ 'wp.compose.pure is deprecated since version 7.1. Please use Use `memo` or `PureComponent` instead instead.'
30
+ );
31
+ expect( screen.getByTestId( 'content' ) ).toHaveTextContent(
32
+ 'content'
33
+ );
101
34
  } );
102
35
  } );
@@ -2,7 +2,7 @@
2
2
 
3
3
  A hook to facilitate drag and drop handling within a designated drop zone area. An optional `dropZoneElement` can be provided, however by default the drop zone is bound by the area where the returned `ref` is assigned.
4
4
 
5
- When using a `dropZoneElement`, it is expected that the `ref` will be attached to a node that is a descendent of the `dropZoneElement`. Additionally, the element passed to `dropZoneElement` should be stored in state rather than a plain ref to ensure reactive updating when it changes.
5
+ When using a `dropZoneElement`, it is expected that the `ref` will be attached to a node that is a descendant of the `dropZoneElement`. Additionally, the element passed to `dropZoneElement` should be stored in state rather than a plain ref to ensure reactive updating when it changes.
6
6
 
7
7
  ## Usage
8
8
 
@@ -19,8 +19,11 @@ const EMPTY_SUBSCRIBER: MQLSubscriber = {
19
19
  getValue: () => false,
20
20
  };
21
21
 
22
- function getMQLSubscriber( view: Window, query?: string ): MQLSubscriber {
23
- if ( ! query || typeof view?.matchMedia !== 'function' ) {
22
+ function getMQLSubscriber(
23
+ view: Window | undefined,
24
+ query?: string
25
+ ): MQLSubscriber {
26
+ if ( ! view || ! query || typeof view.matchMedia !== 'function' ) {
24
27
  return EMPTY_SUBSCRIBER;
25
28
  }
26
29
 
@@ -75,7 +78,11 @@ function getMQLSubscriber( view: Window, query?: string ): MQLSubscriber {
75
78
  */
76
79
  export default function useMediaQuery(
77
80
  query?: string,
78
- view: Window = window
81
+ // Resolve the default lazily so SSR (where `window` is undeclared) does not
82
+ // throw a ReferenceError when this default expression is evaluated.
83
+ view: Window | undefined = typeof window !== 'undefined'
84
+ ? window
85
+ : undefined
79
86
  ): boolean {
80
87
  const source = getMQLSubscriber( view, query );
81
88
 
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+
5
+ /**
6
+ * External dependencies
7
+ */
8
+ import { renderToString } from 'react-dom/server';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import useMediaQuery from '../';
14
+ import useViewportMatch from '../../use-viewport-match';
15
+
16
+ const MediaQueryComponent = ( { query } ) => {
17
+ const result = useMediaQuery( query );
18
+ return `useMediaQuery: ${ result }`;
19
+ };
20
+
21
+ const ViewportMatchComponent = ( { breakpoint, operator } ) => {
22
+ const result = useViewportMatch( breakpoint, operator );
23
+ return `useViewportMatch: ${ result }`;
24
+ };
25
+
26
+ describe( 'compose hooks in a server (no-window) environment', () => {
27
+ it( 'useMediaQuery renders to false without throwing when window is undefined', () => {
28
+ expect( typeof window ).toBe( 'undefined' );
29
+ expect(
30
+ renderToString( <MediaQueryComponent query="(min-width: 782px)" /> )
31
+ ).toBe( 'useMediaQuery: false' );
32
+ } );
33
+
34
+ it( 'useMediaQuery renders to false when no query is provided', () => {
35
+ expect( renderToString( <MediaQueryComponent /> ) ).toBe(
36
+ 'useMediaQuery: false'
37
+ );
38
+ } );
39
+
40
+ it( 'useViewportMatch renders to false without throwing when window is undefined', () => {
41
+ expect(
42
+ renderToString(
43
+ <ViewportMatchComponent breakpoint="small" operator=">=" />
44
+ )
45
+ ).toBe( 'useViewportMatch: false' );
46
+ } );
47
+ } );
@@ -4,12 +4,33 @@
4
4
  import { useRef, useCallback, useLayoutEffect } from '@wordpress/element';
5
5
  import type { MutableRefObject, Ref, RefCallback } from 'react';
6
6
 
7
- function assignRef< T >( ref: Ref< T >, value: T ) {
7
+ // Returns a cleanup function if the ref callback returned one (React 19 ref
8
+ // callback cleanup pattern), otherwise `undefined`. Object refs never have a
9
+ // cleanup and only set `.current`.
10
+ function assignRef< T >( ref: Ref< T >, value: T ): ( () => void ) | undefined {
8
11
  if ( typeof ref === 'function' ) {
9
- ref( value );
12
+ const returned = ref( value );
13
+ return typeof returned === 'function' ? returned : undefined;
10
14
  } else if ( ref && ref.hasOwnProperty( 'current' ) ) {
11
15
  ( ref as MutableRefObject< T > ).current = value;
12
16
  }
17
+ return undefined;
18
+ }
19
+
20
+ // Tear down a ref at the given index: prefer the stored cleanup; otherwise
21
+ // fall back to calling the ref with `null`.
22
+ function detachRef< T >(
23
+ ref: Ref< T >,
24
+ index: number,
25
+ cleanups: Array< ( () => void ) | undefined >
26
+ ): void {
27
+ const cleanup = cleanups[ index ];
28
+ if ( cleanup ) {
29
+ cleanups[ index ] = undefined;
30
+ cleanup();
31
+ } else {
32
+ assignRef( ref, null );
33
+ }
13
34
  }
14
35
 
15
36
  /**
@@ -28,22 +49,24 @@ function assignRef< T >( ref: Ref< T >, value: T ) {
28
49
  * old ref callback will be called with `null` and the new ref callback will be
29
50
  * called with the same value.
30
51
  *
31
- * To make ref callbacks easier to use, you can also pass the result of
32
- * `useRefEffect`, which makes cleanup easier by allowing you to return a
33
- * cleanup function instead of handling `null`.
52
+ * Inner ref callbacks may return a cleanup function (React 19's ref callback
53
+ * cleanup pattern). When a ref callback returns a function, that function is
54
+ * invoked at teardown (node change, dependency change, or unmount) **instead
55
+ * of** the callback being called with `null`. Callbacks that do not return a
56
+ * cleanup continue to receive `null` on teardown as before.
34
57
  *
35
58
  * It's also possible to _disable_ a ref (and its behaviour) by simply not
36
59
  * passing the ref.
37
60
  *
38
61
  * ```jsx
39
- * const ref = useRefEffect( ( node ) => {
62
+ * const ref = useCallback( ( node ) => {
40
63
  * node.addEventListener( ... );
41
64
  * return () => {
42
65
  * node.removeEventListener( ... );
43
66
  * };
44
67
  * }, [ ...dependencies ] );
45
68
  * const otherRef = useRef();
46
- * const mergedRefs useMergeRefs( [
69
+ * const mergedRefs = useMergeRefs( [
47
70
  * enabled && ref,
48
71
  * otherRef,
49
72
  * ] );
@@ -56,11 +79,15 @@ function assignRef< T >( ref: Ref< T >, value: T ) {
56
79
  export default function useMergeRefs< T >(
57
80
  refs: Ref< T >[]
58
81
  ): RefCallback< T > {
59
- const element = useRef( null );
82
+ const elementRef = useRef< T | null >( null );
60
83
  const isAttachedRef = useRef( false );
61
84
  const didElementChangeRef = useRef( false );
62
85
  const previousRefsRef = useRef< Ref< T >[] >( [] );
63
86
  const currentRefsRef = useRef( refs );
87
+ // Position-indexed cleanups returned by inner ref callbacks. A slot is
88
+ // `undefined` when the ref at that position did not return a cleanup (or
89
+ // is an object ref / disabled).
90
+ const cleanupsRef = useRef< Array< ( () => void ) | undefined > >( [] );
64
91
 
65
92
  // Update on render before the ref callback is called, so the ref callback
66
93
  // always has access to the current refs.
@@ -77,8 +104,11 @@ export default function useMergeRefs< T >(
77
104
  refs.forEach( ( ref, index ) => {
78
105
  const previousRef = previousRefsRef.current[ index ];
79
106
  if ( ref !== previousRef ) {
80
- assignRef( previousRef, null );
81
- assignRef( ref, element.current );
107
+ detachRef( previousRef, index, cleanupsRef.current );
108
+ cleanupsRef.current[ index ] = assignRef(
109
+ ref,
110
+ elementRef.current as T
111
+ );
82
112
  }
83
113
  } );
84
114
  }
@@ -97,20 +127,21 @@ export default function useMergeRefs< T >(
97
127
  return useCallback( ( value: T | null ) => {
98
128
  // Update the element so it can be used when calling ref callbacks on a
99
129
  // dependency change.
100
- assignRef( element, value );
130
+ elementRef.current = value;
101
131
 
102
132
  didElementChangeRef.current = true;
103
133
  isAttachedRef.current = value !== null;
104
134
 
105
135
  // When an element changes, the current ref callback should be called
106
136
  // with the new element and the previous one with `null`.
107
- const refsToAssign = value
108
- ? currentRefsRef.current
109
- : previousRefsRef.current;
110
-
111
- // Update the latest refs.
112
- for ( const ref of refsToAssign ) {
113
- assignRef( ref, value );
137
+ if ( value === null ) {
138
+ previousRefsRef.current.forEach( ( ref, index ) => {
139
+ detachRef( ref, index, cleanupsRef.current );
140
+ } );
141
+ } else {
142
+ currentRefsRef.current.forEach( ( ref, index ) => {
143
+ cleanupsRef.current[ index ] = assignRef( ref, value );
144
+ } );
114
145
  }
115
146
  }, [] );
116
147
  }