@@ -31,8 +31,6 @@ import { store as blockEditorStore } from '../store';
31
31
32
32
const { DropdownMenuV2 } = unlock ( componentsPrivateApis ) ;
33
33
34
- const EMPTY_OBJECT = { } ;
35
-
36
34
const useToolsPanelDropdownMenuProps = ( ) => {
37
35
const isMobile = useViewportMatch ( 'medium' , '<' ) ;
38
36
return ! isMobile
@@ -192,50 +190,51 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
192
190
const bindableAttributes = getBindableAttributes ( blockName ) ;
193
191
const dropdownMenuProps = useToolsPanelDropdownMenuProps ( ) ;
194
192
195
- // `useSelect` is used purposely here to ensure `getFieldsList`
196
- // is updated whenever there are updates in block context.
197
- // `source.getFieldsList` may also call a selector via `registry.select`.
198
- const _fieldsList = { } ;
199
- const { fieldsList, canUpdateBlockBindings } = useSelect (
200
- ( select ) => {
201
- if ( ! bindableAttributes || bindableAttributes . length === 0 ) {
202
- return EMPTY_OBJECT ;
203
- }
204
- const { getBlockBindingsSources } = unlock ( blocksPrivateApis ) ;
205
- const registeredSources = getBlockBindingsSources ( ) ;
206
- Object . entries ( registeredSources ) . forEach (
207
- ( [ sourceName , { getFieldsList, usesContext } ] ) => {
208
- if ( getFieldsList ) {
209
- // Populate context.
210
- const context = { } ;
211
- if ( usesContext ?. length ) {
212
- for ( const key of usesContext ) {
213
- context [ key ] = blockContext [ key ] ;
214
- }
215
- }
216
- const sourceList = getFieldsList ( {
217
- registry,
218
- context,
219
- } ) ;
220
- // Only add source if the list is not empty.
221
- if ( Object . keys ( sourceList || { } ) . length ) {
222
- _fieldsList [ sourceName ] = { ...sourceList } ;
193
+ const { canUpdateBlockBindings } = useSelect ( ( select ) => {
194
+ return {
195
+ canUpdateBlockBindings :
196
+ select ( blockEditorStore ) . getSettings ( ) . canUpdateBlockBindings ,
197
+ } ;
198
+ } , [ ] ) ;
199
+
200
+ /**
201
+ * Create new selector for fieldsList to avoid unnecessary re-renders.
202
+ * See: https://github.com/WordPress/gutenberg/pull/64072#discussion_r1764693730
203
+ *
204
+ * `useSelect` is used purposely here to ensure `getFieldsList` is updated
205
+ * whenever there are updates in block context.
206
+ * `source.getFieldsList` may also call a selector via `registry.select`.
207
+ */
208
+ const fieldsList = useSelect ( ( ) => {
209
+ if ( ! bindableAttributes || bindableAttributes . length === 0 ) {
210
+ return ;
211
+ }
212
+ const _fieldsList = { } ;
213
+ const { getBlockBindingsSources } = unlock ( blocksPrivateApis ) ;
214
+ const registeredSources = getBlockBindingsSources ( ) ;
215
+ Object . entries ( registeredSources ) . forEach (
216
+ ( [ sourceName , { getFieldsList, usesContext } ] ) => {
217
+ if ( getFieldsList ) {
218
+ // Populate context.
219
+ const context = { } ;
220
+ if ( usesContext ?. length ) {
221
+ for ( const key of usesContext ) {
222
+ context [ key ] = blockContext [ key ] ;
223
223
}
224
224
}
225
+ const sourceList = getFieldsList ( {
226
+ registry,
227
+ context,
228
+ } ) ;
229
+ // Only add source if the list is not empty.
230
+ if ( Object . keys ( sourceList || { } ) . length ) {
231
+ _fieldsList [ sourceName ] = { ...sourceList } ;
232
+ }
225
233
}
226
- ) ;
227
- return {
228
- fieldsList :
229
- Object . values ( _fieldsList ) . length > 0
230
- ? _fieldsList
231
- : EMPTY_OBJECT ,
232
- canUpdateBlockBindings :
233
- select ( blockEditorStore ) . getSettings ( )
234
- . canUpdateBlockBindings ,
235
- } ;
236
- } ,
237
- [ blockContext , bindableAttributes , registry ]
238
- ) ;
234
+ }
235
+ ) ;
236
+ return Object . values ( _fieldsList ) . length > 0 && { ..._fieldsList } ;
237
+ } , [ blockContext , bindableAttributes , registry ] ) ;
239
238
// Return early if there are no bindable attributes.
240
239
if ( ! bindableAttributes || bindableAttributes . length === 0 ) {
241
240
return null ;
@@ -254,7 +253,7 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
254
253
255
254
// Lock the UI when the user can't update bindings or there are no fields to connect to.
256
255
const readOnly =
257
- ! canUpdateBlockBindings || ! Object . keys ( fieldsList ) . length ;
256
+ ! canUpdateBlockBindings || ! Object . keys ( fieldsList || { } ) . length ;
258
257
259
258
if ( readOnly && Object . keys ( filteredBindings ) . length === 0 ) {
260
259
return null ;
0 commit comments