Skip to content

Commit 0daa67b

Browse files
authored
Remove value syncing in Link Control (#51387)
* Remove the syncing * Update docs with best practices * Remove unnecessary test coverage * Implement suggestion sync with previous state * Apply update from Code Review
1 parent cd0035d commit 0daa67b

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

packages/block-editor/src/components/link-control/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ Renders a link control. A link control is a controlled input which maintains a v
44

55
It is designed to provide a standardized UI for the creation of a link throughout the Editor, see History section at bottom for further background.
66

7+
## Best Practices
8+
9+
### Ensuring unique instances
10+
11+
It is possible that a given editor may render multiple instances of the `<LinkControl>` component. As a result, it is important to ensure each instance is unique across the editor to avoid state "leaking" between components.
12+
13+
Why would this happen?
14+
15+
React's reconciliation algorithm means that if you return the same element from a component, it keeps the nodes around as an optimization, even if the props change. This means that if you render two (or more) `<LinkControl>`s, it is possible that the `value` from one will appear in the other as you move between them.
16+
17+
As a result it is recommended that consumers provide a `key` prop to each instance of `<LinkControl>`:
18+
19+
```jsx
20+
<LinkControl key="some-unique-key" { ...props } />
21+
```
22+
23+
This will cause React to return the same component/element type but force remount a new instance, thus avoiding the issues described above.
24+
25+
For more information see: https://github.com/WordPress/gutenberg/pull/34742.
26+
727
## Relationship to `<URLInput>`
828

929
As of Gutenberg 7.4, `<LinkControl>` became the default link creation interface within the Block Editor, replacing previous disparate uses of `<URLInput>` and standardizing the UI.

packages/block-editor/src/components/link-control/use-internal-value.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
/**
22
* WordPress dependencies
33
*/
4-
import { useState, useEffect } from '@wordpress/element';
4+
import { useState } from '@wordpress/element';
5+
6+
/**
7+
* External dependencies
8+
*/
9+
import fastDeepEqual from 'fast-deep-equal';
510

611
export default function useInternalValue( value ) {
712
const [ internalValue, setInternalValue ] = useState( value || {} );
13+
const [ previousValue, setPreviousValue ] = useState( value );
814

915
// If the value prop changes, update the internal state.
10-
useEffect( () => {
11-
setInternalValue( ( prevValue ) => {
12-
if ( value && value !== prevValue ) {
13-
return value;
14-
}
15-
16-
return prevValue;
17-
} );
18-
}, [ value ] );
16+
// See:
17+
// - https://github.com/WordPress/gutenberg/pull/51387#issuecomment-1722927384.
18+
// - https://react.dev/reference/react/useState#storing-information-from-previous-renders.
19+
if ( ! fastDeepEqual( value, previousValue ) ) {
20+
setPreviousValue( value );
21+
setInternalValue( value );
22+
}
1923

2024
const setInternalURLInputValue = ( nextValue ) => {
2125
setInternalValue( {

0 commit comments

Comments
 (0)